Modify rankings system to use tiers and reduce weighting (#71)

This commit is contained in:
shavitush 2016-08-08 02:23:06 +03:00
parent 0d8b5db880
commit f3474d2d4c
7 changed files with 394 additions and 620 deletions

View File

@ -119,6 +119,7 @@ Replay
- [x] Make replay bots dead if there's no replay data loaded.
- [x] Clear player cache on spawn/death.
- [x] Add admin interface. (delete replay data, `sm_deletereplay` for RCON admins.
- [ ] Bonus replay for default style.
Stats
--
@ -132,8 +133,8 @@ Stats
- [x] Redo *everything*.
- [x] Add 'last online' field.
- [x] Add `Shavit_GetWRCount(int client)`.
- [x] Stop calculating points on the fly and grab everything from the table.
- [ ] Rework on points sorting and show weighting percentages.
- [ ] Stop calculating points on the fly and grab everything from the table.
Miscellaneous
--
@ -172,16 +173,18 @@ Rankings **(NEW!)**
- [x] Add natives. `float Shavit_GetPoints(int client)` `int Shavit_GetRank(int client)` `void Shavit_GetMapValues(float &points, float &idealtime)`
- [x] Add native that checks the total amount of players with over 0 points.
- [x] Add map tiers. `sm_tier` `sm_settier`
- [ ] Redirect to stats menu from `sm_top`.
- [ ] Deprecate the tables, use a `playertimes` column for map points and a `users` column for total points.
- [ ] Find a way to update newly calculated points for all records on a map with the least amount of queries possible.
- [ ] Remove idealtime and use the WR time for the default time instead.
- [ ] Remove deleted records from `playerpoints`.
- [x] Redirect to stats menu from `sm_top`.
- [x] Deprecate the tables, use a `playertimes` column for map points and a `users` column for total points.
- [x] Find a way to update newly calculated points for all records on a map with the least amount of queries possible.
- [x] Remove idealtime and use the WR time for the default time instead.
- [x] Remove deleted records from `playerpoints`.
- [x] Update every player's total points once per map. (MySQL only)
Web Interface
--
- [x] Implement points.
- [x] Compatibility for unix timestamps.
- [ ] Compatibility for new points.
Chat **(NEW!)**
--
@ -220,7 +223,7 @@ World Records
- [x] Add `sm_recent` `sm_recentrecords` `sm_rr`.
- [x] Add strafes/sync to the WR menu where available.
- [x] Add 'player stats' to submenu.
- [ ] Grab points from `playertimes` instead of calculating on the fly.
- [x] Grab points from `playertimes` instead of calculating on the fly.
- [ ] Add `sm_bwr` `sm_bonuswr` `sm_bonusworldrecord`.
Time Limits

View File

@ -167,7 +167,7 @@ char gS_ShortBhopStyles[MAX_STYLES][] =
#if defined USES_STYLE_MULTIPLIERS
// ranking system
float gI_RankingMultipliers[MAX_STYLES] =
float gF_RankingMultipliers[MAX_STYLES] =
{
1.00, // Normal
1.30, // Sideways
@ -670,27 +670,6 @@ native float Shavit_GetPoints(int client);
*/
native int Shavit_GetRank(int client);
/**
* Gets ranking values for the current map.
* See CalculatePoints() in shavit-rankings.
*
* @param points Reference to map points. -1.0 if not set.
* @param idealtime Reference to ideal time. 0.0 if not set.
* @noreturn
*/
native void Shavit_GetMapValues(float &points, float &idealtime);
/**
* Gets ranking values for a given map.
* See CalculatePoints() in shavit-rankings.
*
* @param map Map to get values from.
* @param points Reference to map points. -1.0 if not set.
* @param idealtime Reference to ideal time. 0.0 if not set.
* @noreturn
*/
native void Shavit_GetGivenMapValues(const char[] map, float &points, float &idealtime);
/**
* Gets the amount of players with over 0 points.
*
@ -698,17 +677,6 @@ native void Shavit_GetGivenMapValues(const char[] map, float &points, float &ide
*/
native int Shavit_GetRankedPlayers();
/**
* Calculates points for given time, style, ideal time and points for the ideal time.
*
* @param time Time.
* @param idealtime Ideal time.
* @param style Bhop style.
* @param mappoints Points for the ideal time
* @return Calculated poiints.
*/
native float Shavit_CalculatePoints(float time, BhopStyle style, float idealtime, float mappoints);
/**
* Force an HUD update for a player. Requires shavit-hud.
*
@ -795,15 +763,12 @@ public SharedPlugin __pl_shavit =
#if !defined REQUIRE_PLUGIN
public void __pl_shavit_SetNTVOptional()
{
MarkNativeAsOptional("Shavit_CalculatePoints");
MarkNativeAsOptional("Shavit_FinishMap");
MarkNativeAsOptional("Shavit_ForceHUDUpdate");
MarkNativeAsOptional("Shavit_FormatChat");
MarkNativeAsOptional("Shavit_GetBhopStyle");
MarkNativeAsOptional("Shavit_GetClientTime");
MarkNativeAsOptional("Shavit_GetClientJumps");
MarkNativeAsOptional("Shavit_GetGivenMapValues");
MarkNativeAsOptional("Shavit_GetMapValues");
MarkNativeAsOptional("Shavit_GetPlayerPB");
MarkNativeAsOptional("Shavit_GetPoints");
MarkNativeAsOptional("Shavit_GetRank");

View File

@ -261,6 +261,8 @@ public void LoadChatCache(int client)
strcopy(gS_Cached_ClanTag[client], 32, sBuffer);
}
}
UpdateClanTag(client);
}
public void ResetCache()

View File

@ -978,8 +978,8 @@ public void SQL_DBConnect()
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 `%susers` (`auth` VARCHAR(32) NOT NULL, `name` VARCHAR(32), `country` VARCHAR(128), `ip` VARCHAR(64), `lastlogin` %s NOT NULL DEFAULT -1, PRIMARY KEY (`auth`));", gS_MySQLPrefix, gB_MySQL? "INT":"INTEGER");
char[] sQuery = new char[512];
FormatEx(sQuery, 512, "CREATE TABLE IF NOT EXISTS `%susers` (`auth` VARCHAR(32) NOT NULL, `name` VARCHAR(32), `country` VARCHAR(128), `ip` VARCHAR(64), `lastlogin` %s NOT NULL DEFAULT -1, `points` FLOAT NOT NULL DEFAULT 0, PRIMARY KEY (`auth`));", gS_MySQLPrefix, gB_MySQL? "INT":"INTEGER");
// CREATE TABLE IF NOT EXISTS
gH_SQL.Query(SQL_CreateTable_Callback, sQuery);
@ -997,6 +997,9 @@ public void SQL_CreateTable_Callback(Database db, DBResultSet results, const cha
char[] sQuery = new char[64];
FormatEx(sQuery, 64, "SELECT lastlogin FROM %susers LIMIT 1;", gS_MySQLPrefix);
gH_SQL.Query(SQL_TableMigration1_Callback, sQuery, 0, DBPrio_High);
FormatEx(sQuery, 64, "SELECT points FROM %susers LIMIT 1;", gS_MySQLPrefix);
gH_SQL.Query(SQL_TableMigration2_Callback, sQuery, 0, DBPrio_High);
}
public void SQL_TableMigration1_Callback(Database db, DBResultSet results, const char[] error, any data)
@ -1019,6 +1022,26 @@ public void SQL_AlterTable1_Callback(Database db, DBResultSet results, const cha
}
}
public void SQL_TableMigration2_Callback(Database db, DBResultSet results, const char[] error, any data)
{
if(results == null)
{
char[] sQuery = new char[128];
FormatEx(sQuery, 128, "ALTER TABLE `%susers` ADD %s;", gS_MySQLPrefix, gB_MySQL? "(`points` FLOAT NOT NULL DEFAULT 0)":"COLUMN `points` FLOAT NOT NULL DEFAULT 0");
gH_SQL.Query(SQL_AlterTable2_Callback, sQuery);
}
}
public void SQL_AlterTable2_Callback(Database db, DBResultSet results, const char[] error, any data)
{
if(results == null)
{
LogError("Timer error! Table alteration 2 (core) failed. Reason: %s", error);
return;
}
}
public void PreThink(int client)
{
sv_airaccelerate.IntValue = (gI_StyleProperties[gBS_Style[client]] & STYLE_100AA)? 100:gI_CachedDefaultAA;

View File

@ -21,6 +21,7 @@
#include <sourcemod>
#undef REQUIRE_PLUGIN
#define USES_STYLE_PROPERTIES
#define USES_STYLE_MULTIPLIERS
#include <shavit>
@ -35,27 +36,22 @@ Handle gH_Forwards_OnRankUpdated = null;
// cache
char gS_Map[256];
float gF_IdealTime = 0.0;
float gF_MapPoints = -1.0;
int gI_NeededRecordsAmount = 0;
int gI_CachedRecordsAmount = 0;
int gI_RankedPlayers = 0;
char gS_CachedMap[MAXPLAYERS+1][192];
int gI_MapTier = -1;
float gF_MapTier = 1.0;
bool gB_ChatMessage[MAXPLAYERS+1];
float gF_PlayerPoints[MAXPLAYERS+1];
int gI_PlayerRank[MAXPLAYERS+1];
bool gB_PointsToChat[MAXPLAYERS+1];
bool gB_CheckRankedPlayers = false;
StringMap gSM_Points = null;
StringMap gSM_Time = null;
// convars
ConVar gCV_TopAmount = null;
ConVar gCV_TiersDB = null;
ConVar gCV_PointsPerTier = null;
ConVar gCV_PlayersToCalculate = null;
// database handles
Database gH_SQL = null;
@ -72,7 +68,7 @@ public Plugin myinfo =
{
name = "[shavit] Rankings",
author = "shavit",
description = "Ranking system for shavit's bhop timer.",
description = "Rankings system for shavit's bhop timer.",
version = SHAVIT_VERSION,
url = "https://github.com/shavitush/bhoptimer"
}
@ -81,10 +77,7 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max
{
CreateNative("Shavit_GetPoints", Native_GetPoints);
CreateNative("Shavit_GetRank", Native_GetRank);
CreateNative("Shavit_GetMapValues", Native_GetMapValues);
CreateNative("Shavit_GetGivenMapValues", Native_GetGivenMapValues);
CreateNative("Shavit_GetRankedPlayers", Native_GetRankedPlayers);
CreateNative("Shavit_CalculatePoints", Native_CalculatePoints);
RegPluginLibrary("shavit-rankings");
@ -101,20 +94,11 @@ public void OnAllPluginsLoaded()
public void OnPluginStart()
{
// cache
gSM_Points = new StringMap();
gSM_Time = new StringMap();
// forwards
gH_Forwards_OnRankUpdated = CreateGlobalForward("Shavit_OnRankUpdated", ET_Event, Param_Cell);
// database connections
Shavit_GetDB(gH_SQL);
SQL_SetPrefix();
SetSQLInfo();
// player commands
RegConsoleCmd("sm_points", Command_Points, "Prints the points and ideal time for the map.");
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.");
@ -123,24 +107,25 @@ public void OnPluginStart()
RegConsoleCmd("sm_maptier", Command_Tier, "Prints the map's tier to chat. (sm_tier alias)");
// admin commands
RegAdminCmd("sm_setpoints", Command_SetPoints, ADMFLAG_ROOT, "Set points for a defined ideal time. sm_setpoints <time in seconds> <points>");
RegAdminCmd("sm_setmappoints", Command_SetPoints, ADMFLAG_ROOT, "Set points for a defined ideal time. sm_setpoints <time in seconds> <points> (sm_setpoints alias)");
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");
#if defined DEBUG
// debug
RegServerCmd("sm_calc", Command_Calc);
#endif
// 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);
AutoExecConfig();
// database connections
Shavit_GetDB(gH_SQL);
SQL_SetPrefix();
SetSQLInfo();
// modules
gB_Stats = LibraryExists("shavit-stats");
}
@ -175,17 +160,8 @@ public void OnClientPutInServer(int client)
gF_PlayerPoints[client] = -1.0;
gI_PlayerRank[client] = -1;
gB_PointsToChat[client] = false;
char[] sAuthID3 = new char[32];
if(GetClientAuthId(client, AuthId_Steam3, sAuthID3, 32))
{
char[] sQuery = new char[128];
FormatEx(sQuery, 128, "SELECT points FROM %suserpoints WHERE auth = '%s' LIMIT 1;", gS_MySQLPrefix, sAuthID3);
gH_SQL.Query(SQL_GetUserPoints_Callback, sQuery, GetClientSerial(client), DBPrio_Low);
}
UpdatePointsToDatabase(client);
if(!gB_ChatMessage[client])
{
@ -195,6 +171,19 @@ public void OnClientPutInServer(int client)
}
}
public 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)
@ -215,20 +204,7 @@ public void SQL_GetUserPoints_Callback(Database db, DBResultSet results, const c
{
gF_PlayerPoints[client] = results.FetchFloat(0);
UpdatePlayerPoints(client, false);
}
else
{
char[] sAuthID3 = new char[32];
if(GetClientAuthId(client, AuthId_Steam3, sAuthID3, 32))
{
char[] sQuery = new char[128];
FormatEx(sQuery, 128, "REPLACE INTO %suserpoints (auth, points) VALUES ('%s', 0.0);", gS_MySQLPrefix, sAuthID3);
gH_SQL.Query(SQL_InsertUser_Callback, sQuery, 0, DBPrio_Low);
}
UpdatePlayerPoints(client);
}
UpdateRankedPlayers();
@ -248,7 +224,7 @@ public Action Timer_PrintTier(Handle Timer, any data)
{
int client = GetClientFromSerial(data);
if(client == 0 || gI_MapTier == -1)
if(client == 0 || gF_MapTier == -1.0)
{
return Plugin_Stop;
}
@ -256,60 +232,25 @@ public Action Timer_PrintTier(Handle Timer, any data)
char[] sDisplayMap = new char[strlen(gS_Map) + 1];
GetMapDisplayName(gS_Map, sDisplayMap, strlen(gS_Map) + 1);
Shavit_PrintToChat(client, "\x04%s\x01 is rated \x05tier %d\x01.", sDisplayMap, gI_MapTier);
Shavit_PrintToChat(client, "\x04%s\x01 is rated \x05tier %.01f\x01.", sDisplayMap, gF_MapTier);
return Plugin_Stop;
}
#if defined DEBUG
public Action Command_Calc(int args)
{
if(args != 4)
{
PrintToServer("no");
return Plugin_Handled;
}
char[] sArg1 = new char[32];
GetCmdArg(1, sArg1, 32);
float fTime = StringToFloat(sArg1);
char[] sArg2 = new char[32];
GetCmdArg(2, sArg2, 32);
BhopStyle style = view_as<BhopStyle>(StringToInt(sArg2));
char[] sArg3 = new char[32];
GetCmdArg(3, sArg3, 32);
float fIdealTime = StringToFloat(sArg3);
char[] sArg4 = new char[32];
GetCmdArg(4, sArg4, 32);
float fMapPoints = StringToFloat(sArg4);
PrintToServer("%.02f", CalculatePoints(fTime, style, fIdealTime, fMapPoints));
return Plugin_Handled;
}
#endif
public void OnMapStart()
{
gI_NeededRecordsAmount = 0;
gI_CachedRecordsAmount = 0;
gF_IdealTime = 0.0;
gF_MapPoints = -1.0;
gF_MapTier = -1.0;
gB_CheckRankedPlayers = false;
GetCurrentMap(gS_Map, 256);
UpdatePointsCache(gS_Map);
if(gH_Tiers != null)
{
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);
}
}
public void SQL_SetTierCache_Callback(Database db, DBResultSet results, const char[] error, any data)
@ -323,12 +264,43 @@ public void SQL_SetTierCache_Callback(Database db, DBResultSet results, const ch
if(results.FetchRow())
{
gI_MapTier = results.FetchInt(0);
gF_MapTier = results.FetchFloat(0);
}
else
char[] sQuery = new char[256];
FormatEx(sQuery, 256, "SELECT auth FROM %susers ORDER BY points DESC LIMIT %d;", gS_MySQLPrefix, (gCV_PlayersToCalculate.IntValue == -1)? gCV_TopAmount.IntValue:gCV_PlayersToCalculate.IntValue);
gH_SQL.Query(SQL_RecalculatePoints_Callback, sQuery);
}
public void SQL_RecalculatePoints_Callback(Database db, DBResultSet results, const char[] error, any data)
{
if(results == null)
{
gI_MapTier = -1;
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);
}
}
@ -339,20 +311,30 @@ public Action Command_Points(int client, int args)
return Plugin_Handled;
}
if(gF_MapPoints == -1.0)
char[] sDisplayMap = new char[strlen(gS_Map) + 1];
GetMapDisplayName(gS_Map, sDisplayMap, strlen(gS_Map) + 1);
float fWRTime = 0.0;
Shavit_GetWRTime(view_as<BhopStyle>(0), fWRTime);
if(fWRTime < 0.0)
{
Shavit_PrintToChat(client, "Points are not defined for this map.");
Shavit_PrintToChat(client, "\x04%s\x01: Unknown points, no records on map.", sDisplayMap);
return Plugin_Handled;
}
char[] sDisplayMap = new char[strlen(gS_Map) + 1];
GetMapDisplayName(gS_Map, sDisplayMap, strlen(gS_Map) + 1);
float fTier = gF_MapTier;
if(fTier == -1.0)
{
fTier = 1.0;
}
char[] sTime = new char[32];
FormatSeconds(gF_IdealTime, sTime, 32, false);
FormatSeconds(fWRTime, sTime, 32, false);
Shavit_PrintToChat(client, "\x04%s\x01: \x03%.01f\x01 points for \x05%s\x01.", sDisplayMap, gF_MapPoints, sTime);
Shavit_PrintToChat(client, "\x04%s\x01: Around \x03%.01f\x01 points for a time of \x05%s\x01.", sDisplayMap, (fTier * gCV_PointsPerTier.FloatValue), sTime);
return Plugin_Handled;
}
@ -404,7 +386,7 @@ public Action Command_Top(int client, int args)
public Action ShowTopMenu(int client)
{
char[] sQuery = new char[192];
FormatEx(sQuery, 192, "SELECT u.name, %s points, u.auth FROM %susers u JOIN %suserpoints up ON up.auth = u.auth WHERE up.points > 0.0 ORDER BY up.points DESC LIMIT %d;", gB_MySQL? "FORMAT(up.points, 2)":"up.points", gS_MySQLPrefix, gS_MySQLPrefix, gCV_TopAmount.IntValue);
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, gCV_TopAmount.IntValue);
gH_SQL.Query(SQL_ShowTopMenu_Callback, sQuery, GetClientSerial(client));
@ -506,9 +488,9 @@ public Action Command_Tier(int client, int args)
char[] sDisplayMap = new char[strlen(gS_Map) + 1];
GetMapDisplayName(gS_Map, sDisplayMap, strlen(gS_Map) + 1);
if(gI_MapTier != -1)
if(gF_MapTier != -1)
{
Shavit_PrintToChat(client, "\x04%s\x01 is rated \x05tier %d\x01.", sDisplayMap, gI_MapTier);
Shavit_PrintToChat(client, "\x04%s\x01 is rated \x05tier %.01f\x01.", sDisplayMap, gF_MapTier);
}
else
@ -554,7 +536,7 @@ public void SQL_GetTier_Callback(Database db, DBResultSet results, const char[]
char[] sDisplayMap = new char[strlen(sMap) + 1];
GetMapDisplayName(sMap, sDisplayMap, strlen(sMap) + 1);
Shavit_PrintToChat(client, "\x04%s\x01 is rated \x05tier %d\x01.", sDisplayMap, gI_MapTier);
Shavit_PrintToChat(client, "\x04%s\x01 is rated \x05tier %.01f\x01.", sDisplayMap, gF_MapTier);
}
else
@ -578,22 +560,21 @@ public Action Command_SetTier(int client, int args)
char[] sArg1 = new char[8];
GetCmdArg(1, sArg1, 8);
int iTier = StringToInt(sArg1);
float fTier = StringToFloat(sArg1);
if(iTier < 0)
if(fTier < 0)
{
ReplyToCommand(client, "Invalid map tier (%d)!", iTier);
ReplyToCommand(client, "Invalid map tier (%.01f)!", fTier);
return Plugin_Handled;
}
gI_MapTier = iTier;
gF_MapTier = fTier;
ReplyToCommand(client, "Map tier is now %d.", iTier);
ReplyToCommand(client, "Map tier is now %.01f.", fTier);
char[] sQuery = new char[256];
FormatEx(sQuery, 256, "REPLACE INTO %smaptiers (map, tier) VALUES ('%s', %d);", gS_MySQLPrefix, gS_Map, iTier);
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;
@ -607,302 +588,100 @@ public void SQL_SetTier_Callback(Database db, DBResultSet results, const char[]
return;
}
UpdateRecordPoints();
}
public Action Command_SetPoints(int client, int args)
public void UpdateRecordPoints()
{
if(args != 2)
if(gF_MapTier == -1.0)
{
char[] sArg0 = new char[32];
GetCmdArg(0, sArg0, 32);
ReplyToCommand(client, "Usage: %s <time in seconds> <points>", sArg0);
return Plugin_Handled;
}
char[] sArg1 = new char[32];
GetCmdArg(1, sArg1, 32);
float fTime = gF_IdealTime = StringToFloat(sArg1);
FormatSeconds(fTime, sArg1, 32, false);
char[] sArg2 = new char[32];
GetCmdArg(2, sArg2, 32);
float fPoints = gF_MapPoints = StringToFloat(sArg2);
if(fTime < 0.0 || fPoints < 0.0)
{
ReplyToCommand(client, "Invalid arguments: {%.01f} {%.01f}", fTime, fPoints);
return Plugin_Handled;
}
ReplyToCommand(client, "Set \x03%.01f\x01 points for \x05%s\x01.", fPoints, sArg1);
SetMapPoints(fTime, fPoints);
return Plugin_Handled;
}
public void SetMapPoints(float time, float points)
{
char[] sQuery = new char[256];
FormatEx(sQuery, 256, "REPLACE INTO %smappoints (map, time, points) VALUES ('%s', '%.01f', '%.01f');", gS_MySQLPrefix, gS_Map, time, points);
gH_SQL.Query(SQL_SetPoints_Callback, sQuery, 0, DBPrio_Low);
}
public void SQL_SetPoints_Callback(Database db, DBResultSet results, const char[] error, any data)
{
if(results == null)
{
LogError("Timer (rankings module) error! Failed to insert map data to the table. Reason: %s", error);
return;
}
float fTier = gF_MapTier;
if(fTier < 0.0)
{
fTier = -fTier;
}
float fDefaultWR = 0.0;
Shavit_GetWRTime(view_as<BhopStyle>(0), fDefaultWR);
char[] sQuery = new char[512];
FormatEx(sQuery, 512, "SELECT pt.id, pt.time, pt.style, mp.time, mp.points FROM %splayertimes pt JOIN %smappoints mp ON pt.map = mp.map WHERE pt.map = '%s';", gS_MySQLPrefix, gS_MySQLPrefix, gS_Map);
gH_SQL.Query(SQL_RetroactivePoints_Callback, sQuery, 0, DBPrio_Low);
for(int i = 0; i < MAX_STYLES; i++)
{
if(gI_StyleProperties[i] & STYLE_UNRANKED)
{
continue;
}
float fStyleWR = 0.0;
Shavit_GetWRTime(view_as<BhopStyle>(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) * %f) WHERE map = '%s' AND style = %d;", gS_MySQLPrefix, fMeasureTime, ((fTier * gCV_PointsPerTier.FloatValue) * gF_RankingMultipliers[i]), gS_Map, i);
gH_SQL.Query(SQL_UpdateRecords_Callback, sQuery, 0, DBPrio_Low);
}
}
public void SQL_RetroactivePoints_Callback(Database db, DBResultSet results, const char[] error, any data)
public void SQL_UpdateRecords_Callback(Database db, DBResultSet results, const char[] error, any data)
{
if(results == null)
{
LogError("Timer (rankings module) error! RetroactivePoints failed. Reason: %s", error);
LogError("Timer (rankings module) error! Update record points failed. Reason: %s", error);
return;
}
gI_NeededRecordsAmount = results.RowCount;
while(results.FetchRow())
{
float fTime = results.FetchFloat(1);
BhopStyle style = view_as<BhopStyle>(results.FetchInt(2));
float fIdealTime = results.FetchFloat(3);
float fMapPoints = results.FetchFloat(4);
float fPoints = CalculatePoints(fTime, style, fIdealTime, fMapPoints);
char[] sQuery = new char[256];
FormatEx(sQuery, 256, "REPLACE INTO %splayerpoints (recordid, points) VALUES ('%d', '%f');", gS_MySQLPrefix, results.FetchInt(0), fPoints);
gH_SQL.Query(SQL_RetroactivePoints_Callback2, sQuery, 0, DBPrio_Low);
gI_CachedRecordsAmount++;
}
}
public void SQL_RetroactivePoints_Callback2(Database db, DBResultSet results, const char[] error, any data)
{
if(results == null)
{
LogError("Timer (rankings module) error! RetroactivePoints2 failed. Reason: %s", error);
return;
}
if(gI_CachedRecordsAmount == gI_NeededRecordsAmount)
{
for(int i = 1; i <= MaxClients; i++)
{
if(IsValidClient(i))
{
OnClientPutInServer(i);
}
}
gI_NeededRecordsAmount = 0;
gI_CachedRecordsAmount = 0;
}
UpdateRankedPlayers();
}
public void UpdateStringMap()
{
char[] sQuery = new char[64];
FormatEx(sQuery, 64, "SELECT * FROM %smappoints;", gS_MySQLPrefix);
gH_SQL.Query(SQL_UpdateStringMap_Callback, sQuery, 0, DBPrio_Low);
}
public void SQL_UpdateStringMap_Callback(Database db, DBResultSet results, const char[] error, any data)
{
if(results == null)
{
LogError("Timer (rankings module) error! Couldn't update stringmap. Reason: %s", error);
return;
}
gSM_Time.Clear();
gSM_Points.Clear();
while(results.FetchRow())
{
char[] sMap = new char[192];
results.FetchString(0, sMap, 192);
float fTime = results.FetchFloat(1);
gSM_Time.SetValue(sMap, fTime);
float fPoints = results.FetchFloat(2);
gSM_Points.SetValue(sMap, fPoints);
}
}
public void UpdatePointsCache(const char[] map)
{
char[] sQuery = new char[192];
FormatEx(sQuery, 192, "SELECT time, points FROM %smappoints WHERE map = '%s' LIMIT 1;", gS_MySQLPrefix, map);
gH_SQL.Query(SQL_UpdateCache_Callback, sQuery, 0, DBPrio_Low);
}
public void SQL_UpdateCache_Callback(Database db, DBResultSet results, const char[] error, any data)
{
if(results == null)
{
LogError("Timer (rankings module) error! Couldn't update points cache. Reason: %s", error);
return;
}
if(results.FetchRow())
{
gF_IdealTime = results.FetchFloat(0);
gF_MapPoints = results.FetchFloat(1);
}
for(int i = 1; i <= MaxClients; i++)
{
if(IsValidClient(i))
{
OnClientPutInServer(i);
UpdatePlayerPoints(i);
}
}
UpdateStringMap();
}
// a ***very simple*** 'aglorithm' that calculates points for a given time while taking into account the following: bhop style, ideal time and map points for the ideal time
public float CalculatePoints(float time, BhopStyle style, float idealtime, float mappoints)
public void WeighPoints(const char[] auth, int serial)
{
if(gF_IdealTime < 0.0 || gF_MapPoints < 0.0)
{
return -1.0; // something's wrong! map points might be undefined.
}
float points = ((mappoints / (time/idealtime)) * gI_RankingMultipliers[style]);
if(time <= idealtime)
{
points *= 1.25;
}
return points;
}
public void Shavit_OnFinish_Post(int client, BhopStyle style, float time)
{
#if defined DEBUG
Shavit_PrintToChat(client, "Points: %.02f", CalculatePoints(time, style, gF_IdealTime, gF_MapPoints));
#endif
if(gF_MapPoints <= 0.0 || gF_IdealTime <= 0.0)
if(!gB_MySQL)
{
return;
}
float fPoints = CalculatePoints(time, style, gF_IdealTime, gF_MapPoints);
Shavit_PrintToChat(client, "This record was rated \x05%.02f points\x01.", fPoints);
SavePoints(GetClientSerial(client), style, gS_Map, fPoints, "");
}
public void SavePoints(int serial, BhopStyle style, const char[] map, float points, const char[] authid)
{
char[] sAuthID = new char[32];
if(strlen(authid) == 0)
{
int client = GetClientFromSerial(serial);
if(client == 0)
{
LogError("Couldn't find client from serial %d.", serial);
return;
}
else
{
GetClientAuthId(client, AuthId_Steam3, sAuthID, 32);
}
}
else
{
strcopy(sAuthID, 32, authid);
}
DataPack dp = new DataPack();
dp.WriteCell(serial);
dp.WriteString(sAuthID);
dp.WriteString(map);
dp.WriteCell(style);
dp.WriteCell(points);
char[] sQuery = new char[256];
FormatEx(sQuery, 256, "SELECT id FROM %splayertimes WHERE auth = '%s' AND map = '%s' AND style = %d LIMIT 1;", gS_MySQLPrefix, sAuthID, map, style);
FormatEx(sQuery, 256, "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_FindRecordID_Callback, sQuery, dp, DBPrio_Low);
gH_SQL.Query(SQL_WeighPoints_Callback, sQuery, serial, DBPrio_Low);
}
public void SQL_FindRecordID_Callback(Database db, DBResultSet results, const char[] error, any data)
{
ResetPack(data);
int serial = ReadPackCell(data);
char[] sAuthID = new char[32];
ReadPackString(data, sAuthID, 32);
char[] sMap = new char[192];
ReadPackString(data, sMap, 192);
BhopStyle style = ReadPackCell(data);
float fPoints = ReadPackCell(data);
CloseHandle(data);
if(results == null)
{
LogError("Timer (rankings module) error! FindRecordID query failed. Reason: %s", error);
return;
}
if(results.FetchRow())
{
char[] sQuery = new char[256];
FormatEx(sQuery, 256, "REPLACE INTO %splayerpoints (recordid, points) VALUES ('%d', '%f');", gS_MySQLPrefix, results.FetchInt(0), fPoints);
gH_SQL.Query(SQL_InsertPoints_Callback, sQuery, serial, DBPrio_Low);
}
else // just loop endlessly until it's in the database. if hosted locally, it should be instantly available!
{
SavePoints(serial, style, sMap, fPoints, sAuthID);
}
}
public void SQL_InsertPoints_Callback(Database db, DBResultSet results, const char[] error, any data)
public void SQL_WeighPoints_Callback(Database db, DBResultSet results, const char[] error, any data)
{
if(results == null)
{
LogError("Timer (rankings module) error! Insertion of %d (serial) points to table failed. Reason: %s", data, error);
LogError("Timer (rankings module) error! Weighing of points failed. Reason: %s", error);
return;
}
@ -911,30 +690,65 @@ public void SQL_InsertPoints_Callback(Database db, DBResultSet results, const ch
if(client != 0)
{
UpdatePlayerPoints(client, true);
UpdatePlayerPoints(client);
}
UpdateRankedPlayers();
}
public void UpdatePlayerPoints(int client, bool chat)
public float CalculatePoints(float time, BhopStyle style, float tier)
{
float fWRTime = 0.0;
Shavit_GetWRTime(view_as<BhopStyle>(0), fWRTime);
if(tier <= 0.0 || fWRTime <= 0.0)
{
return gCV_PointsPerTier.FloatValue;
}
return (((fWRTime / time) * (tier * gCV_PointsPerTier.FloatValue)) * gF_RankingMultipliers[style]);
}
public void Shavit_OnFinish_Post(int client, BhopStyle 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
float fPoints = CalculatePoints(time, style, (gF_MapTier == -1.0)? 1.0:gF_MapTier);
Shavit_PrintToChat(client, "This record was rated \x05%.02f points\x01.", fPoints);
UpdateRecordPoints();
CreateTimer(5.0, DelayedPointsUpdate, GetClientSerial(client), TIMER_FLAG_NO_MAPCHANGE);
}
public Action DelayedPointsUpdate(Handle Timer, any data)
{
int client = GetClientFromSerial(data);
if(client != 0)
{
UpdatePointsToDatabase(client);
}
return Plugin_Stop;
}
public void UpdatePlayerPoints(int client)
{
if(!IsClientAuthorized(client))
{
return;
}
gB_PointsToChat[client] = chat;
char[] sAuthID = new char[32];
GetClientAuthId(client, AuthId_Steam3, sAuthID, 32);
char[] sQuery = new char[256];
FormatEx(sQuery, 256, "SELECT points FROM %splayertimes pt JOIN %splayerpoints pp ON pt.id = pp.recordid WHERE pt.auth = '%s' AND pp.points != -1 ORDER BY pp.points DESC;", gS_MySQLPrefix, gS_MySQLPrefix, sAuthID);
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)
@ -957,13 +771,6 @@ public void SQL_UpdatePoints_Callback(Database db, DBResultSet results, const ch
if(client != 0)
{
if(gB_PointsToChat[client])
{
Shavit_PrintToChat(client, "Total points: \x05%.02f\x01.", fPoints);
gB_PointsToChat[client] = false;
}
gF_PlayerPoints[client] = fPoints;
char[] sAuthID3 = new char[32];
@ -971,11 +778,9 @@ public void SQL_UpdatePoints_Callback(Database db, DBResultSet results, const ch
if(GetClientAuthId(client, AuthId_Steam3, sAuthID3, 32))
{
char[] sQuery = new char[256];
FormatEx(sQuery, 256, "UPDATE %suserpoints SET points = '%f' WHERE auth = '%s';", gS_MySQLPrefix, fPoints, sAuthID3);
FormatEx(sQuery, 256, "UPDATE %susers SET points = '%f' WHERE auth = '%s';", gS_MySQLPrefix, fPoints, sAuthID3);
gH_SQL.Query(SQL_UpdatePointsTable_Callback, sQuery, 0, DBPrio_Low);
UpdatePlayerRank(client);
}
}
}
@ -988,16 +793,31 @@ public void SQL_UpdatePointsTable_Callback(Database db, DBResultSet results, con
return;
}
int client = GetClientFromSerial(data);
for(int i = 1; i <= MaxClients; i++)
{
if(IsValidClient(i))
{
UpdatePlayerRank(client);
}
}
}
public void UpdatePlayerRank(int client)
{
if(!IsValidClient(client))
{
return;
}
char[] sAuthID3 = new char[32];
if(GetClientAuthId(client, AuthId_Steam3, sAuthID3, 32))
{
char[] sQuery = new char[256];
FormatEx(sQuery, 256, "SELECT COUNT(*) rank FROM %suserpoints up LEFT JOIN %susers u ON up.auth = u.auth WHERE up.points >= (SELECT points FROM %suserpoints WHERE auth = '%s' LIMIT 1) ORDER BY up.points DESC LIMIT 1;", gS_MySQLPrefix, gS_MySQLPrefix, gS_MySQLPrefix, sAuthID3);
FormatEx(sQuery, 256, "SELECT COUNT(*) rank FROM %susers u WHERE points >= (SELECT points FROM %susers WHERE auth = '%s' LIMIT 1) ORDER BY u.points DESC LIMIT 1;", gS_MySQLPrefix, gS_MySQLPrefix, sAuthID3);
gH_SQL.Query(SQL_UpdatePlayerRank_Callback, sQuery, GetClientSerial(client), DBPrio_Low);
}
@ -1039,8 +859,7 @@ public void SQL_UpdatePlayerRank_Callback(Database db, DBResultSet results, cons
public void UpdateRankedPlayers()
{
char[] sQuery = new char[128];
FormatEx(sQuery, 128, "SELECT COUNT(*) FROM %suserpoints WHERE points > 0 LIMIT 1;", gS_MySQLPrefix);
FormatEx(sQuery, 128, "SELECT COUNT(*) FROM %susers WHERE points > 0.0 LIMIT 1;", gS_MySQLPrefix);
gH_SQL.Query(SQL_UpdateRankedPlayers_Callback, sQuery);
}
@ -1058,11 +877,14 @@ public void SQL_UpdateRankedPlayers_Callback(Database db, DBResultSet results, c
gI_RankedPlayers = results.FetchInt(0);
}
UpdateStringMap();
gB_CheckRankedPlayers = false;
}
public void Shavit_OnWRDeleted()
{
UpdateRecordPoints();
}
public int Native_GetPoints(Handle handler, int numParams)
{
return view_as<int>(gF_PlayerPoints[GetNativeCell(1)]);
@ -1073,46 +895,11 @@ public int Native_GetRank(Handle handler, int numParams)
return gI_PlayerRank[GetNativeCell(1)];
}
public int Native_GetMapValues(Handle handler, int numParams)
{
SetNativeCellRef(1, gF_MapPoints);
SetNativeCellRef(2, gF_IdealTime);
}
public int Native_GetGivenMapValues(Handle handler, int numParams)
{
char[] map = new char[192];
GetNativeString(1, map, 192);
float fPoints = -1.0;
if(!gSM_Points.GetValue(map, fPoints))
{
fPoints = -1.0;
}
SetNativeCellRef(2, fPoints);
float fTime = 0.0;
if(!gSM_Time.GetValue(map, fTime))
{
fTime = 0.0;
}
SetNativeCellRef(3, fTime);
}
public int Native_GetRankedPlayers(Handle handler, int numParams)
{
return gI_RankedPlayers;
}
public int Native_CalculatePoints(Handle handler, int numParams)
{
return view_as<int>(CalculatePoints(GetNativeCell(1), GetNativeCell(2), GetNativeCell(3), GetNativeCell(4)));
}
public Action CheckForSQLInfo(Handle Timer)
{
return SetSQLInfo();
@ -1169,21 +956,15 @@ public void SQL_DBConnect()
{
if(gH_SQL != null)
{
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 `%smappoints` (`map` VARCHAR(192), `time` FLOAT, `points` FLOAT, PRIMARY KEY (`map`));", gS_MySQLPrefix);
gH_SQL.Query(SQL_CreateTable_Callback, sQuery, 0, DBPrio_High);
FormatEx(sQuery, 256, "CREATE TABLE IF NOT EXISTS `%splayerpoints` (`recordid` INT NOT NULL, `points` FLOAT, PRIMARY KEY (`recordid`));", gS_MySQLPrefix);
gH_SQL.Query(SQL_CreateTable_Callback, sQuery, 0, DBPrio_High);
FormatEx(sQuery, 256, "CREATE TABLE IF NOT EXISTS `%suserpoints` (`auth` VARCHAR(32), `points` FLOAT, PRIMARY KEY (`auth`));", gS_MySQLPrefix);
gH_SQL.Query(SQL_CreateTable_Callback, sQuery, 0, DBPrio_High);
char[] sError = new char[255];
if(gCV_TiersDB.BoolValue)
{
gH_Tiers = gH_SQL;
}
else
{
gH_Tiers = SQLite_UseDatabase("shavit-tiers", sError, 255);
if(gH_Tiers == null)
@ -1192,8 +973,17 @@ public void SQL_DBConnect()
return;
}
}
OnMapStart();
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);
FormatEx(sQuery, 256, "CREATE TABLE IF NOT EXISTS `%smaptiers` (`map` VARCHAR(192), `tier` INT, PRIMARY KEY (`map`));", gS_MySQLPrefix);
gH_Tiers.Query(SQL_CreateTable_Callback, sQuery, 0, DBPrio_High);
}
}
@ -1207,5 +997,5 @@ public void SQL_CreateTable_Callback(Database db, DBResultSet results, const cha
return;
}
UpdatePointsCache(gS_Map);
OnMapStart();
}

View File

@ -294,14 +294,13 @@ public Action OpenStatsMenu(int client, const char[] authid)
if(gB_Rankings)
{
FormatEx(sQuery, 2048, "SELECT a.clears, b.maps, c.wrs, d.name, d.country, d.lastlogin, e.rank, f.points FROM " ...
FormatEx(sQuery, 2048, "SELECT a.clears, b.maps, c.wrs, d.name, d.country, d.lastlogin, d.points, e.rank FROM " ...
"(SELECT COUNT(*) clears FROM (SELECT id FROM %splayertimes WHERE auth = '%s' GROUP BY map) s LIMIT 1) a " ...
"JOIN (SELECT COUNT(*) maps FROM (SELECT id FROM %smapzones GROUP BY map) s LIMIT 1) b " ...
"JOIN (SELECT COUNT(*) wrs FROM (SELECT s.auth FROM (SELECT style, auth, MIN(time) FROM %splayertimes GROUP BY map, style) s WHERE style = 0) ss WHERE ss.auth = '%s' LIMIT 1) c " ...
"JOIN (SELECT name, country, lastlogin FROM %susers WHERE auth = '%s' LIMIT 1) d " ...
"JOIN (SELECT COUNT(*) rank FROM %suserpoints up LEFT JOIN %susers u ON up.auth = u.auth WHERE up.points >= (SELECT points FROM %suserpoints WHERE auth = '%s' LIMIT 1) ORDER BY up.points DESC LIMIT 1) e " ...
"JOIN (SELECT points FROM %suserpoints WHERE auth = '%s' LIMIT 1) f " ...
"LIMIT 1;", gS_MySQLPrefix, authid, gS_MySQLPrefix, gS_MySQLPrefix, authid, gS_MySQLPrefix, authid, gS_MySQLPrefix, gS_MySQLPrefix, gS_MySQLPrefix, authid, gS_MySQLPrefix, authid);
"JOIN (SELECT name, country, lastlogin, points FROM %susers WHERE auth = '%s' LIMIT 1) d " ...
"JOIN (SELECT COUNT(*) rank FROM %susers WHERE points >= (SELECT points FROM %susers WHERE auth = '%s' LIMIT 1) ORDER BY points DESC LIMIT 1) e " ...
"LIMIT 1;", gS_MySQLPrefix, authid, gS_MySQLPrefix, gS_MySQLPrefix, authid, gS_MySQLPrefix, authid, gS_MySQLPrefix, gS_MySQLPrefix, authid);
}
else
@ -356,8 +355,8 @@ public void OpenStatsMenuCallback(Database db, DBResultSet results, const char[]
if(gB_Rankings)
{
iRank = results.FetchInt(6);
fPoints = results.FetchFloat(7);
fPoints = results.FetchFloat(6);
iRank = results.FetchInt(7);
}
char[] sRankingString = new char[64];
@ -492,7 +491,7 @@ public void ShowMaps(int client)
if(gI_MapType[client] == MAPSDONE)
{
FormatEx(sQuery, 512, "SELECT a.map, a.time, a.jumps, a.id, COUNT(b.map) + 1 rank FROM %splayertimes a LEFT JOIN %splayertimes b ON a.time > b.time AND a.map = b.map AND a.style = b.style WHERE a.auth = '%s' AND a.style = %d GROUP BY a.map ORDER BY a.map;", gS_MySQLPrefix, gS_MySQLPrefix, gS_TargetAuth[client], view_as<int>(gBS_Style[client]));
FormatEx(sQuery, 512, "SELECT a.map, a.time, a.jumps, a.id, COUNT(b.map) + 1 rank, a.points FROM %splayertimes a LEFT JOIN %splayertimes b ON a.time > b.time AND a.map = b.map AND a.style = b.style WHERE a.auth = '%s' AND a.style = %d GROUP BY a.map ORDER BY a.%s;", gS_MySQLPrefix, gS_MySQLPrefix, gS_TargetAuth[client], view_as<int>(gBS_Style[client]), (gB_Rankings)? "points":"map");
}
else
@ -554,22 +553,14 @@ public void ShowMapsCallback(Database db, DBResultSet results, const char[] erro
char[] sTime = new char[32];
FormatSeconds(fTime, sTime, 32);
bool bPoints = false;
float fPoints = results.FetchFloat(5);
if(gB_Rankings)
if(gB_Rankings && fPoints > 0.0)
{
float fPoints = 0.0;
float fIdealTime = -1.0;
Shavit_GetGivenMapValues(sMap, fPoints, fIdealTime);
if(fPoints != -1.0 && fIdealTime != 0.0)
{
FormatEx(sDisplay, 192, "[#%d] %s - %s (%.03f points)", iRank, sMap, sTime, Shavit_CalculatePoints(fTime, gBS_Style[client], fIdealTime, fPoints));
bPoints = true;
}
FormatEx(sDisplay, 192, "[#%d] %s - %s (%.03f points)", iRank, sMap, sTime, fPoints);
}
if(!bPoints)
else
{
FormatEx(sDisplay, 192, "[#%d] %s - %s (%d jumps)", iRank, sMap, sTime, iJumps);
}
@ -612,7 +603,7 @@ public int MenuHandler_ShowMaps(Menu m, MenuAction action, int param1, int param
}
char[] sQuery = new char[512];
FormatEx(sQuery, 512, "SELECT u.name, p.time, p.jumps, p.style, u.auth, p.date, p.map, p.strafes, p.sync FROM %splayertimes p JOIN %susers u ON p.auth = u.auth WHERE p.id = '%s' LIMIT 1;", gS_MySQLPrefix, gS_MySQLPrefix, sInfo);
FormatEx(sQuery, 512, "SELECT u.name, p.time, p.jumps, p.style, u.auth, p.date, p.map, p.strafes, p.sync, p.points FROM %splayertimes p JOIN %susers u ON p.auth = u.auth WHERE p.id = '%s' LIMIT 1;", gS_MySQLPrefix, gS_MySQLPrefix, sInfo);
gH_SQL.Query(SQL_SubMenu_Callback, sQuery, GetClientSerial(param1));
}
@ -682,18 +673,13 @@ public void SQL_SubMenu_Callback(Database db, DBResultSet results, const char[]
// 6 - map
results.FetchString(6, sMap, 256);
if(gB_Rankings)
{
float fPoints = 0.0;
float fIdealTime = -1.0;
Shavit_GetGivenMapValues(sMap, fPoints, fIdealTime);
float fPoints = results.FetchFloat(9);
if(fPoints != -1.0 && fIdealTime != 0.0)
if(gB_Rankings && fPoints > 0.0)
{
FormatEx(sDisplay, 192, "Points: %.03f", Shavit_CalculatePoints(fTime, bsStyle, fIdealTime, fPoints));
FormatEx(sDisplay, 192, "Points: %.03f", fPoints);
m.AddItem("-1", sDisplay);
}
}
// 5 - date
char[] sDate = new char[32];

View File

@ -517,22 +517,6 @@ public int MenuHandler_DeleteAll(Menu m, MenuAction action, int param1, int para
return 0;
}
for(int i = 0; i < MAX_STYLES; i++)
{
if(gI_StyleProperties[i] & STYLE_UNRANKED)
{
continue;
}
if(gF_WRTime[i] != 0.0)
{
Call_StartForward(gH_OnWRDeleted);
Call_PushCell(i);
Call_PushCell(-1);
Call_Finish();
}
}
char[] sQuery = new char[256];
FormatEx(sQuery, 256, "DELETE FROM %splayertimes WHERE map = '%s';", gS_MySQLPrefix, gS_Map);
@ -706,14 +690,11 @@ public int DeleteConfirm_Handler(Menu m, MenuAction action, int param1, int para
continue;
}
if(gF_WRTime[i] != 0.0)
{
Call_StartForward(gH_OnWRDeleted);
Call_PushCell(i);
Call_PushCell(iRecordID);
Call_Finish();
}
}
char[] sQuery = new char[256];
FormatEx(sQuery, 256, "DELETE FROM %splayertimes WHERE id = %d;", gS_MySQLPrefix, iRecordID);
@ -778,6 +759,19 @@ public void DeleteAll_Callback(Database db, DBResultSet results, const char[] er
return;
}
for(int i = 0; i < MAX_STYLES; i++)
{
if(gI_StyleProperties[i] & STYLE_UNRANKED)
{
continue;
}
Call_StartForward(gH_OnWRDeleted);
Call_PushCell(i);
Call_PushCell(-1);
Call_Finish();
}
Shavit_PrintToChat(client, "Deleted ALL records for \"%s\".", gS_Map);
}
@ -1032,7 +1026,7 @@ public Action Command_RecentRecords(int client, int args)
}
char[] sQuery = new char[512];
FormatEx(sQuery, 512, "SELECT p.id, p.map, u.name, MIN(p.time), p.jumps, p.style FROM %splayertimes p JOIN %susers u ON p.auth = u.auth GROUP BY p.map, p.style ORDER BY date DESC LIMIT %d;", gS_MySQLPrefix, gS_MySQLPrefix, gCV_RecentLimit.IntValue);
FormatEx(sQuery, 512, "SELECT p.id, p.map, u.name, MIN(p.time), p.jumps, p.style, p.points FROM %splayertimes p JOIN %susers u ON p.auth = u.auth GROUP BY p.map, p.style ORDER BY date DESC LIMIT %d;", gS_MySQLPrefix, gS_MySQLPrefix, gCV_RecentLimit.IntValue);
gH_SQL.Query(SQL_RR_Callback, sQuery, GetClientSerial(client), DBPrio_High);
@ -1075,25 +1069,16 @@ public void SQL_RR_Callback(Database db, DBResultSet results, const char[] error
int iJumps = results.FetchInt(4);
BhopStyle bsStyle = view_as<BhopStyle>(results.FetchInt(5));
float fPoints = results.FetchFloat(6);
char[] sDisplay = new char[192];
bool bPoints = false;
if(gB_Rankings)
if(gB_Rankings && fPoints > 0.0)
{
float fPoints = 0.0;
float fIdealTime = -1.0;
Shavit_GetGivenMapValues(sMap, fPoints, fIdealTime);
if(fPoints != -1.0 && fIdealTime != 0.0)
{
FormatEx(sDisplay, 192, "[%s] %s - %s @ %s (%.03f points)", gS_ShortBhopStyles[bsStyle], sDisplayMap, sName, sTime, Shavit_CalculatePoints(fTime, bsStyle, fIdealTime, fPoints));
bPoints = true;
}
FormatEx(sDisplay, 192, "[%s] %s - %s @ %s (%.03f points)", gS_ShortBhopStyles[bsStyle], sDisplayMap, sName, sTime, fPoints);
}
if(!bPoints)
else
{
FormatEx(sDisplay, 192, "[%s] %s - %s @ %s (%d jump%s)", gS_ShortBhopStyles[bsStyle], sDisplayMap, sName, sTime, iJumps, (iJumps != 1)? "s":"");
}
@ -1110,7 +1095,6 @@ public void SQL_RR_Callback(Database db, DBResultSet results, const char[] error
}
m.ExitButton = true;
m.Display(client, 60);
}
@ -1153,7 +1137,7 @@ public int RRMenu_Handler(Menu m, MenuAction action, int param1, int param2)
public void OpenSubMenu(int client, int id)
{
char[] sQuery = new char[512];
FormatEx(sQuery, 512, "SELECT u.name, p.time, p.jumps, p.style, u.auth, p.date, p.map, p.strafes, p.sync FROM %splayertimes p JOIN %susers u ON p.auth = u.auth WHERE p.id = %d LIMIT 1;", gS_MySQLPrefix, gS_MySQLPrefix, id);
FormatEx(sQuery, 512, "SELECT u.name, p.time, p.jumps, p.style, u.auth, p.date, p.map, p.strafes, p.sync, p.points FROM %splayertimes p JOIN %susers u ON p.auth = u.auth WHERE p.id = %d LIMIT 1;", gS_MySQLPrefix, gS_MySQLPrefix, id);
gH_SQL.Query(SQL_SubMenu_Callback, sQuery, GetClientSerial(client), DBPrio_High);
}
@ -1210,18 +1194,13 @@ public void SQL_SubMenu_Callback(Database db, DBResultSet results, const char[]
results.FetchString(6, sMap, 192);
GetMapDisplayName(sMap, sDisplayMap, 192);
if(gB_Rankings)
{
float fPoints = 0.0;
float fIdealTime = -1.0;
Shavit_GetGivenMapValues(sMap, fPoints, fIdealTime);
float fPoints = results.FetchFloat(9);
if(fPoints != -1.0 && fIdealTime != 0.0)
if(gB_Rankings && fPoints > 0.0)
{
FormatEx(sDisplay, 128, "Points: %.03f", Shavit_CalculatePoints(fTime, bsStyle, fIdealTime, fPoints));
FormatEx(sDisplay, 128, "Points: %.03f", fPoints);
m.AddItem("-1", sDisplay);
}
}
// 4 - steamid3
results.FetchString(4, sAuthID, 32);
@ -1337,8 +1316,8 @@ public void SQL_DBConnect()
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 `%splayertimes` (`id` %s, `auth` VARCHAR(32), `map` VARCHAR(192), `time` FLOAT, `jumps` INT, `style` INT, `date` VARCHAR(32), `strafes` INT, `sync` FLOAT%s);", gS_MySQLPrefix, gB_MySQL? "INT NOT NULL AUTO_INCREMENT":"INTEGER PRIMARY KEY", gB_MySQL? ", PRIMARY KEY (`id`)":"");
char[] sQuery = new char[512];
FormatEx(sQuery, 512, "CREATE TABLE IF NOT EXISTS `%splayertimes` (`id` %s, `auth` VARCHAR(32), `map` VARCHAR(192), `time` FLOAT, `jumps` INT, `style` INT, `date` VARCHAR(32), `strafes` INT, `sync` FLOAT, `points` FLOAT NOT NULL DEFAULT 0%s);", gS_MySQLPrefix, gB_MySQL? "INT NOT NULL AUTO_INCREMENT":"INTEGER PRIMARY KEY", gB_MySQL? ", PRIMARY KEY (`id`)":"");
gH_SQL.Query(SQL_CreateTable_Callback, sQuery, 0, DBPrio_High);
}
@ -1372,6 +1351,9 @@ public void SQL_CreateTable_Callback(Database db, DBResultSet results, const cha
FormatEx(sQuery, 64, "ALTER TABLE %splayertimes MODIFY date VARCHAR(32);", gS_MySQLPrefix);
gH_SQL.Query(SQL_AlterTable2_Callback, sQuery);
}
FormatEx(sQuery, 64, "SELECT points FROM %splayertimes LIMIT 1;", gS_MySQLPrefix);
gH_SQL.Query(SQL_TableMigration3_Callback, sQuery);
}
public void SQL_TableMigration1_Callback(Database db, DBResultSet results, const char[] error, any data)
@ -1417,6 +1399,26 @@ public void SQL_AlterTable2_Callback(Database db, DBResultSet results, const cha
}
}
public void SQL_TableMigration3_Callback(Database db, DBResultSet results, const char[] error, any data)
{
if(results == null)
{
char[] sQuery = new char[256];
FormatEx(sQuery, 256, "ALTER TABLE `%splayertimes` ADD %s;", gS_MySQLPrefix, gB_MySQL? "(`points` FLOAT NOT NULL DEFAULT 0)":"COLUMN `points` FLOAT NOT NULL DEFAULT 0");
gH_SQL.Query(SQL_AlterTable3_Callback, sQuery);
}
}
public void SQL_AlterTable3_Callback(Database db, DBResultSet results, const char[] error, any data)
{
if(results == null)
{
LogError("Timer (WR module) error! Times' table migration (3) failed. Reason: %s", error);
return;
}
}
public void Shavit_OnFinish(int client, BhopStyle style, float time, int jumps, int strafes, float sync)
{
char[] sTime = new char[32];
@ -1442,10 +1444,10 @@ public void Shavit_OnFinish(int client, BhopStyle style, float time, int jumps,
overwrite = 2;
}
int iRank = GetRankForTime(style, time);
if(overwrite > 0 && (time < gF_WRTime[style] || gF_WRTime[style] == 0.0)) // WR?
{
gF_WRTime[style] = time;
Call_StartForward(gH_OnWorldRecord);
Call_PushCell(client);
Call_PushCell(style);
@ -1458,6 +1460,8 @@ public void Shavit_OnFinish(int client, BhopStyle style, float time, int jumps,
UpdateWRCache();
}
int iRank = GetRankForTime(style, time);
float fDifference = (gF_PlayerRecord[client][style] - time);
if(fDifference < 0.0)
@ -1513,11 +1517,6 @@ public void Shavit_OnFinish(int client, BhopStyle style, float time, int jumps,
Call_Finish();
gF_PlayerRecord[client][style] = time;
if(time < gF_WRTime[style])
{
gF_WRTime[style] = time;
}
}
else if(overwrite == 0 && !(gI_StyleProperties[style] & STYLE_UNRANKED))
@ -1570,6 +1569,7 @@ public void SQL_UpdateLeaderboards_Callback(Database db, DBResultSet results, co
for(int i = 0; i < MAX_STYLES; i++)
{
gI_RecordAmount[i] = 0;
gA_LeaderBoard[i].Clear();
}
@ -1599,6 +1599,11 @@ public void SQL_UpdateLeaderboards_Callback(Database db, DBResultSet results, co
public int GetRankForTime(BhopStyle style, float time)
{
if(time < gF_WRTime[style])
{
return 1;
}
for(int i = 0; i < gI_RecordAmount[style]; i++)
{
if(time < gA_LeaderBoard[style].Get(i))