mirror of
https://github.com/shavitush/bhoptimer.git
synced 2025-12-06 18:08:26 +00:00
1060 lines
24 KiB
SourcePawn
1060 lines
24 KiB
SourcePawn
/*
|
|
* shavit's Timer - Rankings
|
|
* by: shavit
|
|
*
|
|
* This file is part of shavit's Timer.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it under
|
|
* the terms of the GNU General Public License, version 3.0, as published by the
|
|
* Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include <sourcemod>
|
|
|
|
#undef REQUIRE_PLUGIN
|
|
#include <shavit>
|
|
|
|
#pragma newdecls required
|
|
#pragma semicolon 1
|
|
#pragma dynamic 131072
|
|
|
|
// #define DEBUG
|
|
|
|
// forwards
|
|
Handle gH_Forwards_OnRankUpdated = null;
|
|
|
|
// cache
|
|
char gS_Map[256];
|
|
int gI_RankedPlayers = 0;
|
|
|
|
char gS_CachedMap[MAXPLAYERS+1][192];
|
|
float gF_MapTier = 1.0;
|
|
bool gB_ChatMessage[MAXPLAYERS+1];
|
|
|
|
float gF_PlayerPoints[MAXPLAYERS+1];
|
|
int gI_PlayerRank[MAXPLAYERS+1];
|
|
|
|
bool gB_CheckRankedPlayers = false;
|
|
|
|
bool gB_Late = false;
|
|
|
|
// convars
|
|
ConVar gCV_TopAmount = null;
|
|
ConVar gCV_TiersDB = null;
|
|
ConVar gCV_PointsPerTier = null;
|
|
ConVar gCV_PlayersToCalculate = null;
|
|
|
|
// cached cvars
|
|
int gI_TopAmount = 100;
|
|
bool gB_TiersDB = false;
|
|
float gF_PointsPerTier = 25.0;
|
|
int gI_PlayersToCalculate = -1;
|
|
|
|
// database handles
|
|
Database gH_SQL = null;
|
|
Database gH_Tiers = null;
|
|
bool gB_MySQL = false;
|
|
bool gB_TiersTable = false;
|
|
|
|
// table prefix
|
|
char gS_MySQLPrefix[32];
|
|
|
|
// modules
|
|
bool gB_Stats = false;
|
|
|
|
// timer settings
|
|
int gI_Styles = 0;
|
|
any gA_StyleSettings[STYLE_LIMIT][STYLESETTINGS_SIZE];
|
|
|
|
// chat settings
|
|
char gS_ChatStrings[CHATSETTINGS_SIZE][128];
|
|
|
|
public Plugin myinfo =
|
|
{
|
|
name = "[shavit] Rankings",
|
|
author = "shavit",
|
|
description = "Rankings system for shavit's bhop timer.",
|
|
version = SHAVIT_VERSION,
|
|
url = "https://github.com/shavitush/bhoptimer"
|
|
}
|
|
|
|
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
|
|
{
|
|
CreateNative("Shavit_GetPoints", Native_GetPoints);
|
|
CreateNative("Shavit_GetRank", Native_GetRank);
|
|
CreateNative("Shavit_GetRankedPlayers", Native_GetRankedPlayers);
|
|
|
|
RegPluginLibrary("shavit-rankings");
|
|
|
|
gB_Late = late;
|
|
|
|
return APLRes_Success;
|
|
}
|
|
|
|
public void OnAllPluginsLoaded()
|
|
{
|
|
if(!LibraryExists("shavit-wr"))
|
|
{
|
|
SetFailState("shavit-wr is required for the plugin to work.");
|
|
}
|
|
}
|
|
|
|
public void OnPluginStart()
|
|
{
|
|
// forwards
|
|
gH_Forwards_OnRankUpdated = CreateGlobalForward("Shavit_OnRankUpdated", ET_Event, Param_Cell);
|
|
|
|
// player commands
|
|
RegConsoleCmd("sm_points", Command_Points, "Prints the points you will get for a time on the default style.");
|
|
RegConsoleCmd("sm_rank", Command_Rank, "Shows your current rank.");
|
|
RegConsoleCmd("sm_prank", Command_Rank, "Shows your current rank. (sm_rank alias)");
|
|
RegConsoleCmd("sm_top", Command_Top, "Shows the top players menu.");
|
|
RegConsoleCmd("sm_ptop", Command_Top, "Shows the top players menu. (sm_top alias)");
|
|
RegConsoleCmd("sm_tier", Command_Tier, "Prints the map's tier to chat.");
|
|
RegConsoleCmd("sm_maptier", Command_Tier, "Prints the map's tier to chat. (sm_tier alias)");
|
|
|
|
// admin commands
|
|
RegAdminCmd("sm_settier", Command_SetTier, ADMFLAG_ROOT, "Set map tier. Has no effect except for sm_tier output or message upon connection.");
|
|
RegAdminCmd("sm_setmaptier", Command_SetTier, ADMFLAG_ROOT, "Set map tier. Has no effect except for sm_tier output or message upon connection. (sm_settier alias)");
|
|
|
|
// translations
|
|
LoadTranslations("common.phrases");
|
|
LoadTranslations("shavit-rankings.phrases");
|
|
|
|
// cvars
|
|
gCV_TopAmount = CreateConVar("shavit_rankings_topamount", "100", "Amount of people to show within the sm_top menu.", 0, true, 1.0, false);
|
|
gCV_TiersDB = CreateConVar("shavit_rankings_tiersdb", "0", "If set to 1, use the `shavit` database to store map tiers.\nOtherwise, use a local SQLite database for them.", 0, true, 0.0, true, 1.0);
|
|
gCV_PointsPerTier = CreateConVar("shavit_rankings_pointspertier", "25", "Points for default style's WR per map tier.\nFor example: if you set this value to 50 and you get a #1 Normal record, you will receive 50 points and players below you will receive less.\nIf a map has no tier set, it will reward as if it's tier 1.", 0, true, 1.0);
|
|
gCV_PlayersToCalculate = CreateConVar("shavit_rankings_playerstocalculate", "-1", "(MySQL only!) Amount of players to have their points re-calculated per new map.\nSet to -1 if you want it to use the value of \"shavit_rankings_topamount\".", 0, true, -1.0, true, 250.0);
|
|
|
|
gCV_TopAmount.AddChangeHook(OnConVarChanged);
|
|
gCV_TiersDB.AddChangeHook(OnConVarChanged);
|
|
gCV_PointsPerTier.AddChangeHook(OnConVarChanged);
|
|
gCV_PlayersToCalculate.AddChangeHook(OnConVarChanged);
|
|
|
|
AutoExecConfig();
|
|
|
|
// database connections
|
|
Shavit_GetDB(gH_SQL);
|
|
SQL_SetPrefix();
|
|
SetSQLInfo();
|
|
|
|
// modules
|
|
gB_Stats = LibraryExists("shavit-stats");
|
|
}
|
|
|
|
public void OnConVarChanged(ConVar convar, const char[] oldValue, const char[] newValue)
|
|
{
|
|
gI_TopAmount = gCV_TopAmount.IntValue;
|
|
gB_TiersDB = gCV_TiersDB.BoolValue;
|
|
gF_PointsPerTier = gCV_PointsPerTier.FloatValue;
|
|
gI_PlayersToCalculate = gCV_PlayersToCalculate.IntValue;
|
|
}
|
|
|
|
public void OnLibraryAdded(const char[] name)
|
|
{
|
|
if(StrEqual(name, "shavit-stats"))
|
|
{
|
|
gB_Stats = true;
|
|
}
|
|
}
|
|
|
|
public void OnLibraryRemoved(const char[] name)
|
|
{
|
|
if(StrEqual(name, "shavit-stats"))
|
|
{
|
|
gB_Stats = false;
|
|
}
|
|
}
|
|
|
|
public void OnClientAuthorized(int client, const char[] auth)
|
|
{
|
|
gB_ChatMessage[client] = false;
|
|
}
|
|
|
|
public void OnClientPutInServer(int client)
|
|
{
|
|
if(IsFakeClient(client))
|
|
{
|
|
return;
|
|
}
|
|
|
|
gF_PlayerPoints[client] = -1.0;
|
|
gI_PlayerRank[client] = -1;
|
|
|
|
if(!gB_ChatMessage[client])
|
|
{
|
|
CreateTimer(5.0, Timer_PrintTier, GetClientSerial(client), TIMER_FLAG_NO_MAPCHANGE);
|
|
|
|
gB_ChatMessage[client] = true;
|
|
}
|
|
|
|
if(gH_SQL != null && gH_Tiers != null)
|
|
{
|
|
UpdatePlayerRank(client);
|
|
}
|
|
}
|
|
|
|
void UpdatePointsToDatabase(int client)
|
|
{
|
|
char[] sAuthID3 = new char[32];
|
|
|
|
if(GetClientAuthId(client, AuthId_Steam3, sAuthID3, 32))
|
|
{
|
|
char[] sQuery = new char[128];
|
|
FormatEx(sQuery, 128, "SELECT points FROM %susers WHERE auth = '%s' LIMIT 1;", gS_MySQLPrefix, sAuthID3);
|
|
|
|
gH_SQL.Query(SQL_GetUserPoints_Callback, sQuery, GetClientSerial(client), DBPrio_Low);
|
|
}
|
|
}
|
|
|
|
public void SQL_GetUserPoints_Callback(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if(results == null)
|
|
{
|
|
LogError("Timer error on GetUserPoints. Reason: %s", error);
|
|
|
|
return;
|
|
}
|
|
|
|
int client = GetClientFromSerial(data);
|
|
|
|
if(client == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(results.FetchRow())
|
|
{
|
|
gF_PlayerPoints[client] = results.FetchFloat(0);
|
|
|
|
UpdatePlayerPoints(client);
|
|
}
|
|
|
|
UpdateRankedPlayers();
|
|
}
|
|
|
|
public void SQL_InsertUser_Callback(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if(results == null)
|
|
{
|
|
LogError("Timer error on InsertUser. Reason: %s", error);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
public Action Timer_PrintTier(Handle Timer, any data)
|
|
{
|
|
int client = GetClientFromSerial(data);
|
|
|
|
if(client == 0 || gF_MapTier == -1.0)
|
|
{
|
|
return Plugin_Stop;
|
|
}
|
|
|
|
char[] sDisplayMap = new char[strlen(gS_Map) + 1];
|
|
GetMapDisplayName(gS_Map, sDisplayMap, strlen(gS_Map) + 1);
|
|
|
|
Shavit_PrintToChat(client, "%T", "Tier", client, gS_ChatStrings[sMessageVariable2], sDisplayMap, gS_ChatStrings[sMessageText], gS_ChatStrings[sMessageVariable2], gF_MapTier, gS_ChatStrings[sMessageText]);
|
|
|
|
return Plugin_Stop;
|
|
}
|
|
|
|
public void OnMapStart()
|
|
{
|
|
gF_MapTier = -1.0;
|
|
gB_CheckRankedPlayers = false;
|
|
|
|
GetCurrentMap(gS_Map, 256);
|
|
|
|
if(gH_Tiers != null && gB_TiersTable)
|
|
{
|
|
char[] sQuery = new char[256];
|
|
FormatEx(sQuery, 256, "SELECT tier FROM %smaptiers WHERE map = '%s';", gS_MySQLPrefix, gS_Map);
|
|
|
|
gH_Tiers.Query(SQL_SetTierCache_Callback, sQuery, 0, DBPrio_High);
|
|
}
|
|
|
|
if(gB_Late)
|
|
{
|
|
Shavit_OnStyleConfigLoaded(-1);
|
|
Shavit_OnChatConfigLoaded();
|
|
}
|
|
}
|
|
|
|
public void SQL_SetTierCache_Callback(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if(results == null)
|
|
{
|
|
LogError("Timer (rankings module) error! Set tier cache failed. Reason: %s", error);
|
|
|
|
return;
|
|
}
|
|
|
|
if(results.FetchRow())
|
|
{
|
|
gF_MapTier = results.FetchFloat(0);
|
|
}
|
|
|
|
char[] sQuery = new char[256];
|
|
FormatEx(sQuery, 256, "SELECT auth FROM %susers ORDER BY points DESC LIMIT %d;", gS_MySQLPrefix, (gI_PlayersToCalculate == -1)? gI_TopAmount:gI_PlayersToCalculate);
|
|
|
|
gH_SQL.Query(SQL_RecalculatePoints_Callback, sQuery);
|
|
}
|
|
|
|
public void SQL_RecalculatePoints_Callback(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if(results == null)
|
|
{
|
|
LogError("Timer error on RecalculatePoints. Reason: %s", error);
|
|
|
|
return;
|
|
}
|
|
|
|
while(results.FetchRow())
|
|
{
|
|
char[] sAuthID = new char[32];
|
|
results.FetchString(0, sAuthID, 32);
|
|
|
|
int iSerial = 0;
|
|
char[] sTempAuthID = new char[32];
|
|
|
|
for(int i = 1; i <= MaxClients; i++)
|
|
{
|
|
if(IsValidClient(i) && GetClientAuthId(i, AuthId_Steam3, sTempAuthID, 32) && StrEqual(sTempAuthID, sAuthID))
|
|
{
|
|
iSerial = GetClientSerial(i);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
WeighPoints(sAuthID, iSerial);
|
|
}
|
|
}
|
|
|
|
public void Shavit_OnStyleConfigLoaded(int styles)
|
|
{
|
|
if(styles == -1)
|
|
{
|
|
styles = Shavit_GetStyleCount();
|
|
}
|
|
|
|
for(int i = 0; i < styles; i++)
|
|
{
|
|
Shavit_GetStyleSettings(i, gA_StyleSettings[i]);
|
|
}
|
|
|
|
gI_Styles = styles;
|
|
}
|
|
|
|
public void Shavit_OnChatConfigLoaded()
|
|
{
|
|
for(int i = 0; i < CHATSETTINGS_SIZE; i++)
|
|
{
|
|
Shavit_GetChatStrings(i, gS_ChatStrings[i], 128);
|
|
}
|
|
}
|
|
|
|
public Action Command_Points(int client, int args)
|
|
{
|
|
if(!IsValidClient(client))
|
|
{
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
char[] sDisplayMap = new char[strlen(gS_Map) + 1];
|
|
GetMapDisplayName(gS_Map, sDisplayMap, strlen(gS_Map) + 1);
|
|
|
|
float fWRTime = 0.0;
|
|
Shavit_GetWRTime(0, fWRTime);
|
|
|
|
if(fWRTime < 0.0)
|
|
{
|
|
Shavit_PrintToChat(client, "%T", "UnknownPoints", client, gS_ChatStrings[sMessageVariable], sDisplayMap, gS_ChatStrings[sMessageText]);
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
float fTier = gF_MapTier;
|
|
|
|
if(fTier == -1.0)
|
|
{
|
|
fTier = 1.0;
|
|
}
|
|
|
|
char[] sTime = new char[32];
|
|
FormatSeconds(fWRTime, sTime, 32, false);
|
|
|
|
Shavit_PrintToChat(client, "%T", "ApproximatePoints", client, gS_ChatStrings[sMessageVariable], sDisplayMap, gS_ChatStrings[sMessageText], gS_ChatStrings[sMessageVariable2], (fTier * gF_PointsPerTier), gS_ChatStrings[sMessageText], gS_ChatStrings[sMessageVariable], sTime, gS_ChatStrings[sMessageText]);
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public Action Command_Rank(int client, int args)
|
|
{
|
|
if(!IsValidClient(client))
|
|
{
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
int target = client;
|
|
|
|
if(args > 0)
|
|
{
|
|
char[] sTarget = new char[MAX_TARGET_LENGTH];
|
|
GetCmdArgString(sTarget, MAX_TARGET_LENGTH);
|
|
|
|
target = FindTarget(client, sTarget, true, false);
|
|
|
|
if(target == -1)
|
|
{
|
|
return Plugin_Handled;
|
|
}
|
|
}
|
|
|
|
if(gI_PlayerRank[target] <= 0)
|
|
{
|
|
Shavit_PrintToChat(client, "%T", "Unranked", client, gS_ChatStrings[sMessageVariable2], target, gS_ChatStrings[sMessageText], gS_ChatStrings[sMessageWarning], gS_ChatStrings[sMessageText]);
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
Shavit_PrintToChat(client, "%T", "Rank", client, gS_ChatStrings[sMessageVariable2], target, gS_ChatStrings[sMessageText], gS_ChatStrings[sMessageVariable], gI_PlayerRank[target], gS_ChatStrings[sMessageText], gS_ChatStrings[sMessageVariable], gI_RankedPlayers, gS_ChatStrings[sMessageText], gS_ChatStrings[sMessageVariable], gF_PlayerPoints[target], gS_ChatStrings[sMessageText]);
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public Action Command_Top(int client, int args)
|
|
{
|
|
if(!IsValidClient(client))
|
|
{
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
return ShowTopMenu(client);
|
|
}
|
|
|
|
Action ShowTopMenu(int client)
|
|
{
|
|
char[] sQuery = new char[192];
|
|
FormatEx(sQuery, 192, "SELECT name, %s points, auth FROM %susers WHERE points > 0.0 ORDER BY points DESC LIMIT %d;", gB_MySQL? "FORMAT(points, 2)":"points", gS_MySQLPrefix, gI_TopAmount);
|
|
|
|
gH_SQL.Query(SQL_ShowTopMenu_Callback, sQuery, GetClientSerial(client));
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public void SQL_ShowTopMenu_Callback(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if(results == null)
|
|
{
|
|
LogError("Timer error on ShowTopMenu. Reason: %s", error);
|
|
|
|
return;
|
|
}
|
|
|
|
int client = GetClientFromSerial(data);
|
|
|
|
if(client == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Menu m = new Menu(MenuHandler_TopMenu);
|
|
m.SetTitle("%T", "TopMenuTitle", client, gI_TopAmount);
|
|
|
|
if(results.RowCount == 0)
|
|
{
|
|
char[] sRankItem = new char[64];
|
|
FormatEx(sRankItem, 64, "%T", "TopNoResults", client);
|
|
m.AddItem("-1", sRankItem);
|
|
}
|
|
|
|
else
|
|
{
|
|
int count = 0;
|
|
|
|
while(results.FetchRow())
|
|
{
|
|
char[] sName = new char[MAX_NAME_LENGTH];
|
|
results.FetchString(0, sName, MAX_NAME_LENGTH);
|
|
|
|
int iRank = ++count;
|
|
|
|
char[] sDisplay = new char[64];
|
|
|
|
if(gB_MySQL)
|
|
{
|
|
char[] sPoints = new char[16];
|
|
results.FetchString(1, sPoints, 16);
|
|
|
|
FormatEx(sDisplay, 64, "%T", "TopMenuClients", client, iRank, sName, sPoints);
|
|
}
|
|
|
|
else
|
|
{
|
|
FormatEx(sDisplay, 64, "%T", "TopMenuClients", client, iRank, sName, results.FetchFloat(1));
|
|
}
|
|
|
|
char[] sAuthID = new char[32];
|
|
results.FetchString(2, sAuthID, 32);
|
|
|
|
m.AddItem(sAuthID, sDisplay);
|
|
}
|
|
}
|
|
|
|
m.ExitButton = true;
|
|
|
|
m.Display(client, 20);
|
|
}
|
|
|
|
public int MenuHandler_TopMenu(Menu m, MenuAction action, int param1, int param2)
|
|
{
|
|
if(action == MenuAction_Select && gB_Stats)
|
|
{
|
|
char[] sInfo = new char[32];
|
|
m.GetItem(param2, sInfo, 32);
|
|
|
|
if(StringToInt(sInfo) != -1)
|
|
{
|
|
Shavit_OpenStatsMenu(param1, sInfo);
|
|
}
|
|
}
|
|
|
|
else if(action == MenuAction_End)
|
|
{
|
|
delete m;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
public Action Command_Tier(int client, int args)
|
|
{
|
|
if(!IsValidClient(client))
|
|
{
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
if(args == 0)
|
|
{
|
|
char[] sDisplayMap = new char[strlen(gS_Map) + 1];
|
|
GetMapDisplayName(gS_Map, sDisplayMap, strlen(gS_Map) + 1);
|
|
|
|
if(gF_MapTier != -1)
|
|
{
|
|
Shavit_PrintToChat(client, "%T", "Tier", client, gS_ChatStrings[sMessageVariable], sDisplayMap, gS_ChatStrings[sMessageText], gS_ChatStrings[sMessageVariable2], gF_MapTier, gS_ChatStrings[sMessageText]);
|
|
}
|
|
|
|
else
|
|
{
|
|
Shavit_PrintToChat(client, "%T", "TierUnset", client, gS_ChatStrings[sMessageVariable], sDisplayMap, gS_ChatStrings[sMessageText]);
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
GetCmdArg(1, gS_CachedMap[client], 192);
|
|
|
|
char[] sQuery = new char[256];
|
|
FormatEx(sQuery, 256, "SELECT map, tier FROM %smaptiers WHERE map LIKE '%%%s%%';", gS_MySQLPrefix, gS_CachedMap[client]);
|
|
|
|
gH_Tiers.Query(SQL_GetTier_Callback, sQuery, GetClientSerial(client), DBPrio_High);
|
|
}
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public void SQL_GetTier_Callback(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if(results == null)
|
|
{
|
|
LogError("Timer (rankings module) error! Get map tier failed. Reason: %s", error);
|
|
|
|
return;
|
|
}
|
|
|
|
int client = GetClientFromSerial(data);
|
|
|
|
if(client == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(results.FetchRow())
|
|
{
|
|
char[] sMap = new char[192];
|
|
results.FetchString(0, sMap, 192);
|
|
|
|
char[] sDisplayMap = new char[strlen(sMap) + 1];
|
|
GetMapDisplayName(sMap, sDisplayMap, strlen(sMap) + 1);
|
|
|
|
Shavit_PrintToChat(client, "%T", "Tier", client, gS_ChatStrings[sMessageVariable], sDisplayMap, gS_ChatStrings[sMessageText], gS_ChatStrings[sMessageVariable2], results.FetchFloat(1), gS_ChatStrings[sMessageText]);
|
|
}
|
|
|
|
else
|
|
{
|
|
Shavit_PrintToChat(client, "%T", "TierUnset", client, gS_ChatStrings[sMessageVariable], gS_CachedMap[client], gS_ChatStrings[sMessageText]);
|
|
}
|
|
}
|
|
|
|
public Action Command_SetTier(int client, int args)
|
|
{
|
|
if(args != 1)
|
|
{
|
|
char[] sArg0 = new char[32];
|
|
GetCmdArg(0, sArg0, 32);
|
|
|
|
ReplyToCommand(client, "%T", "TierCommand", client, sArg0);
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
char[] sArg1 = new char[8];
|
|
GetCmdArg(1, sArg1, 8);
|
|
|
|
float fTier = StringToFloat(sArg1);
|
|
|
|
if(fTier < 0)
|
|
{
|
|
ReplyToCommand(client, "%T", "TierInvalid", client, fTier);
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
gF_MapTier = fTier;
|
|
|
|
ReplyToCommand(client, "%T", "TierSet", client, fTier);
|
|
|
|
char[] sQuery = new char[256];
|
|
FormatEx(sQuery, 256, "REPLACE INTO %smaptiers (map, tier) VALUES ('%s', %.1f);", gS_MySQLPrefix, gS_Map, fTier);
|
|
gH_Tiers.Query(SQL_SetTier_Callback, sQuery, GetClientSerial(client), DBPrio_High);
|
|
|
|
return Plugin_Handled;
|
|
}
|
|
|
|
public void SQL_SetTier_Callback(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if(results == null)
|
|
{
|
|
LogError("Timer (rankings module) error! Set map tier failed. Reason: %s", error);
|
|
|
|
return;
|
|
}
|
|
|
|
UpdateRecordPoints();
|
|
}
|
|
|
|
void UpdateRecordPoints()
|
|
{
|
|
if(gF_MapTier == -1.0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
float fTier = gF_MapTier;
|
|
|
|
if(fTier < 0.0)
|
|
{
|
|
fTier = -fTier;
|
|
}
|
|
|
|
float fDefaultWR = 0.0;
|
|
Shavit_GetWRTime(0, fDefaultWR);
|
|
|
|
char[] sQuery = new char[512];
|
|
|
|
for(int i = 0; i < gI_Styles; i++)
|
|
{
|
|
if(gA_StyleSettings[i][bUnranked])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
float fStyleWR = 0.0;
|
|
Shavit_GetWRTime(i, fStyleWR);
|
|
|
|
float fMeasureTime = 0.0;
|
|
|
|
if(fDefaultWR <= 0.0)
|
|
{
|
|
if(fStyleWR <= 0.0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
else
|
|
{
|
|
fMeasureTime = fStyleWR;
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
fMeasureTime = fDefaultWR;
|
|
}
|
|
|
|
FormatEx(sQuery, 512, "UPDATE %splayertimes SET points = ((%.02f / time) * %.02f) WHERE map = '%s' AND style = %d;", gS_MySQLPrefix, fMeasureTime, ((fTier * gF_PointsPerTier) * view_as<float>(gA_StyleSettings[i][fRankingMultiplier])), gS_Map, i);
|
|
gH_SQL.Query(SQL_UpdateRecords_Callback, sQuery, 0, DBPrio_Low);
|
|
}
|
|
}
|
|
|
|
public void SQL_UpdateRecords_Callback(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if(results == null)
|
|
{
|
|
LogError("Timer (rankings module) error! Update record points failed. Reason: %s", error);
|
|
|
|
return;
|
|
}
|
|
|
|
for(int i = 1; i <= MaxClients; i++)
|
|
{
|
|
if(IsValidClient(i))
|
|
{
|
|
UpdatePlayerPoints(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
void WeighPoints(const char[] auth, int serial)
|
|
{
|
|
if(!gB_MySQL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
char[] sQuery = new char[512];
|
|
FormatEx(sQuery, 512, "UPDATE %susers SET points = (SELECT (points * (@f := 0.98 * @f) / 0.98) sumpoints FROM %splayertimes pt CROSS JOIN (SELECT @f := 1.0) params WHERE auth = '%s' AND points > 0.0 ORDER BY points DESC LIMIT 1) WHERE auth = '%s';", gS_MySQLPrefix, gS_MySQLPrefix, auth, auth);
|
|
|
|
gH_SQL.Query(SQL_WeighPoints_Callback, sQuery, serial, DBPrio_Low);
|
|
}
|
|
|
|
public void SQL_WeighPoints_Callback(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if(results == null)
|
|
{
|
|
LogError("Timer (rankings module) error! Weighing of points failed. Reason: %s", error);
|
|
|
|
return;
|
|
}
|
|
|
|
int client = GetClientFromSerial(data);
|
|
|
|
if(client != 0)
|
|
{
|
|
UpdatePlayerPoints(client);
|
|
}
|
|
}
|
|
|
|
#if defined DEBUG
|
|
float CalculatePoints(float time, BhopStyle style, float tier)
|
|
{
|
|
float fWRTime = 0.0;
|
|
Shavit_GetWRTime(0, fWRTime);
|
|
|
|
if(tier <= 0.0 || fWRTime <= 0.0)
|
|
{
|
|
return gF_PointsPerTier;
|
|
}
|
|
|
|
return (((fWRTime / time) * (tier * gF_PointsPerTier)) * view_as<float>(gA_StyleSettings[style][fRankingMultiplier]));
|
|
}
|
|
#endif
|
|
|
|
public void Shavit_OnFinish_Post(int client, int style, float time, int jumps, int strafes, float sync, int rank)
|
|
{
|
|
#if defined DEBUG
|
|
Shavit_PrintToChat(client, "Points: %.02f", CalculatePoints(time, style, gF_IdealTime, gF_MapPoints));
|
|
#endif
|
|
|
|
UpdateRecordPoints();
|
|
}
|
|
|
|
void UpdatePlayerPoints(int client)
|
|
{
|
|
if(!IsClientAuthorized(client))
|
|
{
|
|
return;
|
|
}
|
|
|
|
char[] sAuthID = new char[32];
|
|
GetClientAuthId(client, AuthId_Steam3, sAuthID, 32);
|
|
|
|
char[] sQuery = new char[256];
|
|
FormatEx(sQuery, 256, "SELECT points FROM %splayertimes WHERE auth = '%s' AND points > 0.0 ORDER BY points DESC;", gS_MySQLPrefix, sAuthID);
|
|
gH_SQL.Query(SQL_UpdatePoints_Callback, sQuery, GetClientSerial(client), DBPrio_Low);
|
|
}
|
|
|
|
// would completely deprecate this if we weren't SQLite compatible
|
|
public void SQL_UpdatePoints_Callback(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if(results == null)
|
|
{
|
|
LogError("Timer (rankings module) error! Update of %d (serial) points failed. Reason: %s", data, error);
|
|
|
|
return;
|
|
}
|
|
|
|
float fPoints = 0.0;
|
|
float fWeight = 1.0;
|
|
|
|
while(results.FetchRow())
|
|
{
|
|
fPoints += (results.FetchFloat(0) * fWeight);
|
|
fWeight *= 0.95;
|
|
}
|
|
|
|
int client = GetClientFromSerial(data);
|
|
|
|
if(client != 0)
|
|
{
|
|
gF_PlayerPoints[client] = fPoints;
|
|
|
|
char[] sAuthID3 = new char[32];
|
|
|
|
if(GetClientAuthId(client, AuthId_Steam3, sAuthID3, 32))
|
|
{
|
|
char[] sQuery = new char[256];
|
|
FormatEx(sQuery, 256, "UPDATE %susers SET points = '%.02f' WHERE auth = '%s';", gS_MySQLPrefix, fPoints, sAuthID3);
|
|
|
|
gH_SQL.Query(SQL_UpdatePointsTable_Callback, sQuery, 0, DBPrio_Low);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SQL_UpdatePointsTable_Callback(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if(results == null)
|
|
{
|
|
LogError("Timer (rankings module) error! UpdatePointsTable failed. Reason: %s", error);
|
|
|
|
return;
|
|
}
|
|
|
|
int client = GetClientFromSerial(data);
|
|
|
|
for(int i = 1; i <= MaxClients; i++)
|
|
{
|
|
if(IsValidClient(i))
|
|
{
|
|
UpdatePlayerRank(client);
|
|
}
|
|
}
|
|
}
|
|
|
|
void UpdatePlayerRank(int client)
|
|
{
|
|
if(!IsValidClient(client) || gH_SQL == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
char[] sAuthID3 = new char[32];
|
|
|
|
if(GetClientAuthId(client, AuthId_Steam3, sAuthID3, 32))
|
|
{
|
|
char[] sQuery = new char[256];
|
|
FormatEx(sQuery, 256, "SELECT COUNT(*) rank, points FROM %susers WHERE points >= (SELECT points FROM %susers WHERE auth = '%s' LIMIT 1) ORDER BY points DESC LIMIT 1;", gS_MySQLPrefix, gS_MySQLPrefix, sAuthID3);
|
|
|
|
gH_SQL.Query(SQL_UpdatePlayerRank_Callback, sQuery, GetClientSerial(client), DBPrio_Low);
|
|
}
|
|
}
|
|
|
|
public void SQL_UpdatePlayerRank_Callback(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if(results == null)
|
|
{
|
|
LogError("Timer (rankings module) error! UpdatePlayerRank failed. Reason: %s", error);
|
|
|
|
return;
|
|
}
|
|
|
|
int client = GetClientFromSerial(data);
|
|
|
|
if(client == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(results.FetchRow() && results.FetchFloat(1) > 0.0)
|
|
{
|
|
gI_PlayerRank[client] = results.FetchInt(0);
|
|
|
|
UpdatePointsToDatabase(client);
|
|
|
|
Call_StartForward(gH_Forwards_OnRankUpdated);
|
|
Call_PushCell(client);
|
|
Call_Finish();
|
|
|
|
if(!gB_CheckRankedPlayers)
|
|
{
|
|
UpdateRankedPlayers();
|
|
|
|
gB_CheckRankedPlayers = true;
|
|
}
|
|
}
|
|
|
|
else
|
|
{
|
|
gI_PlayerRank[client] = 0;
|
|
}
|
|
}
|
|
|
|
void UpdateRankedPlayers()
|
|
{
|
|
char[] sQuery = new char[128];
|
|
FormatEx(sQuery, 128, "SELECT COUNT(*) FROM %susers WHERE points > 0.0 LIMIT 1;", gS_MySQLPrefix);
|
|
gH_SQL.Query(SQL_UpdateRankedPlayers_Callback, sQuery);
|
|
}
|
|
|
|
public void SQL_UpdateRankedPlayers_Callback(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if(results == null)
|
|
{
|
|
LogError("Timer (rankings module) error! UpdateRankedPlayers failed. Reason: %s", error);
|
|
|
|
return;
|
|
}
|
|
|
|
if(results.FetchRow())
|
|
{
|
|
gI_RankedPlayers = results.FetchInt(0);
|
|
}
|
|
|
|
gB_CheckRankedPlayers = false;
|
|
}
|
|
|
|
public void Shavit_OnWRDeleted()
|
|
{
|
|
UpdateRecordPoints();
|
|
}
|
|
|
|
public int Native_GetPoints(Handle handler, int numParams)
|
|
{
|
|
return view_as<int>(gF_PlayerPoints[GetNativeCell(1)]);
|
|
}
|
|
|
|
public int Native_GetRank(Handle handler, int numParams)
|
|
{
|
|
return gI_PlayerRank[GetNativeCell(1)];
|
|
}
|
|
|
|
public int Native_GetRankedPlayers(Handle handler, int numParams)
|
|
{
|
|
return gI_RankedPlayers;
|
|
}
|
|
|
|
public Action CheckForSQLInfo(Handle Timer)
|
|
{
|
|
return SetSQLInfo();
|
|
}
|
|
|
|
Action SetSQLInfo()
|
|
{
|
|
if(gH_SQL == null)
|
|
{
|
|
Shavit_GetDB(gH_SQL);
|
|
|
|
CreateTimer(0.5, CheckForSQLInfo);
|
|
}
|
|
|
|
else
|
|
{
|
|
SQL_DBConnect();
|
|
|
|
return Plugin_Stop;
|
|
}
|
|
|
|
return Plugin_Continue;
|
|
}
|
|
|
|
void SQL_SetPrefix()
|
|
{
|
|
char[] sFile = new char[PLATFORM_MAX_PATH];
|
|
BuildPath(Path_SM, sFile, PLATFORM_MAX_PATH, "configs/shavit-prefix.txt");
|
|
|
|
File fFile = OpenFile(sFile, "r");
|
|
|
|
if(fFile == null)
|
|
{
|
|
SetFailState("Cannot open \"configs/shavit-prefix.txt\". Make sure this file exists and that the server has read permissions to it.");
|
|
}
|
|
|
|
char[] sLine = new char[PLATFORM_MAX_PATH*2];
|
|
|
|
while(fFile.ReadLine(sLine, PLATFORM_MAX_PATH*2))
|
|
{
|
|
TrimString(sLine);
|
|
strcopy(gS_MySQLPrefix, 32, sLine);
|
|
|
|
break;
|
|
}
|
|
|
|
delete fFile;
|
|
}
|
|
|
|
void SQL_DBConnect()
|
|
{
|
|
if(gH_SQL != null)
|
|
{
|
|
char[] sError = new char[255];
|
|
|
|
if(gB_TiersDB)
|
|
{
|
|
gH_Tiers = gH_SQL;
|
|
}
|
|
|
|
else
|
|
{
|
|
gH_Tiers = SQLite_UseDatabase("shavit-tiers", sError, 255);
|
|
|
|
if(gH_Tiers == null)
|
|
{
|
|
LogError("Cannot start `shavit-tiers` SQLite table. %s", sError);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
char[] sDriver = new char[8];
|
|
gH_SQL.Driver.GetIdentifier(sDriver, 8);
|
|
gB_MySQL = StrEqual(sDriver, "mysql", false);
|
|
|
|
char[] sQuery = new char[256];
|
|
FormatEx(sQuery, 256, "CREATE TABLE IF NOT EXISTS `%smaptiers` (`map` VARCHAR(192), `tier` FLOAT, PRIMARY KEY (`map`));", gS_MySQLPrefix);
|
|
|
|
gH_Tiers.Query(SQL_CreateTable_Callback, sQuery, 0, DBPrio_High);
|
|
}
|
|
}
|
|
|
|
public void SQL_CreateTable_Callback(Database db, DBResultSet results, const char[] error, any data)
|
|
{
|
|
if(results == null)
|
|
{
|
|
LogError("Timer (rankings module) error! Table creation failed. Reason: %s", error);
|
|
|
|
return;
|
|
}
|
|
|
|
gB_TiersTable = true;
|
|
|
|
OnMapStart();
|
|
}
|
|
|
|
public void Shavit_OnDatabaseLoaded(Database db)
|
|
{
|
|
gH_SQL = db;
|
|
}
|