mirror of
https://github.com/shavitush/bhoptimer.git
synced 2025-12-06 18:08:26 +00:00
huge rework on shavit-stats and add 'last login' (#149)
This commit is contained in:
parent
30433ff79a
commit
3c0f2a857f
@ -91,6 +91,7 @@ Core
|
||||
- [x] Add low gravity styles (0.6).
|
||||
- [x] Better implementation of autobhop and +ds (doublestep fix).
|
||||
- [x] Save autobhop/styles to clientprefs.
|
||||
- [x] Add `lastlogin` column to `users`.
|
||||
- [ ] Add bonus timer.
|
||||
|
||||
HUD
|
||||
@ -128,7 +129,11 @@ Stats
|
||||
- [x] Generate mapsdone points on the fly.
|
||||
- [x] Add map rank to mapsdone.
|
||||
- [x] Show strafes/sync in mapsdone submenu.
|
||||
- [x] Redo *everything*.
|
||||
- [x] Add 'last online' field.
|
||||
- [x] Add `Shavit_GetWRCount(int client)`.
|
||||
- [ ] Rework on points sorting and show weighting percentages.
|
||||
- [ ] Stop calculating points on the fly and grab everything from the table.
|
||||
|
||||
Miscellaneous
|
||||
--
|
||||
@ -167,6 +172,8 @@ 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`.
|
||||
@ -212,6 +219,8 @@ World Records
|
||||
- [x] Calculate points on the fly (sub-menu) instead of grabbing them from `playerpoints`.
|
||||
- [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.
|
||||
- [ ] Add `sm_bwr` `sm_bonuswr` `sm_bonusworldrecord`.
|
||||
|
||||
Time Limits
|
||||
|
||||
@ -734,6 +734,25 @@ native int Shavit_ForceHUDUpdate(int client, bool spectators);
|
||||
*/
|
||||
native int Shavit_FormatChat(int client, const char[] message, const bool team, char[] buffer, int maxlen);
|
||||
|
||||
/**
|
||||
* Opens the stats menu for a client.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @param authid Target SteamID3 to use.
|
||||
* @noreturn
|
||||
*/
|
||||
native void Shavit_OpenStatsMenu(int client, const char[] authid);
|
||||
|
||||
/**
|
||||
* Retrieves the amount of #1 records a player has.
|
||||
* Result will depend on the value of `shavit_stats_mvprankones`.
|
||||
* Called from shavit-stats.
|
||||
*
|
||||
* @param client Client index.
|
||||
* @noreturn
|
||||
*/
|
||||
native int Shavit_GetWRCount(int client);
|
||||
|
||||
/**
|
||||
* Use this native when printing anything in chat if it's related to the timer.
|
||||
* This native will auto-assign colors and a chat prefix.
|
||||
@ -797,12 +816,14 @@ public void __pl_shavit_SetNTVOptional()
|
||||
MarkNativeAsOptional("Shavit_GetSync");
|
||||
MarkNativeAsOptional("Shavit_GetTimer");
|
||||
MarkNativeAsOptional("Shavit_GetTimerStatus");
|
||||
MarkNativeAsOptional("Shavit_GetWRCount");
|
||||
MarkNativeAsOptional("Shavit_GetWRName");
|
||||
MarkNativeAsOptional("Shavit_GetWRRecordID");
|
||||
MarkNativeAsOptional("Shavit_GetWRTime");
|
||||
MarkNativeAsOptional("Shavit_InsideZone");
|
||||
MarkNativeAsOptional("Shavit_IsClientCreatingZone");
|
||||
MarkNativeAsOptional("Shavit_IsReplayDataLoaded");
|
||||
MarkNativeAsOptional("Shavit_OpenStatsMenu");
|
||||
MarkNativeAsOptional("Shavit_PauseTimer");
|
||||
MarkNativeAsOptional("Shavit_PrintToChat");
|
||||
MarkNativeAsOptional("Shavit_RestartTimer");
|
||||
|
||||
@ -147,7 +147,7 @@ public void OnClientSettingsChanged(int client)
|
||||
|
||||
public void UpdateClanTag(int client)
|
||||
{
|
||||
if(strlen(gS_Cached_ClanTag[client]) > 0)
|
||||
if(IsValidClient(client) && strlen(gS_Cached_ClanTag[client]) > 0)
|
||||
{
|
||||
CS_SetClientClanTag(client, gS_Cached_ClanTag[client]);
|
||||
}
|
||||
|
||||
@ -43,6 +43,7 @@ EngineVersion gEV_Type = Engine_Unknown;
|
||||
|
||||
// database handle
|
||||
Database gH_SQL = null;
|
||||
bool gB_MySQL = false;
|
||||
|
||||
// forwards
|
||||
Handle gH_Forwards_Start = null;
|
||||
@ -893,7 +894,7 @@ public void OnClientPutInServer(int client)
|
||||
}
|
||||
|
||||
char[] sQuery = new char[512];
|
||||
FormatEx(sQuery, 512, "REPLACE INTO %susers (auth, name, country, ip) VALUES ('%s', '%s', '%s', '%s');", gS_MySQLPrefix, sAuthID3, sEscapedName, sCountry, sIP);
|
||||
FormatEx(sQuery, 512, "REPLACE INTO %susers (auth, name, country, ip, lastlogin) VALUES ('%s', '%s', '%s', '%s', %d);", gS_MySQLPrefix, sAuthID3, sEscapedName, sCountry, sIP, GetTime());
|
||||
|
||||
gH_SQL.Query(SQL_InsertUser_Callback, sQuery, GetClientSerial(client));
|
||||
}
|
||||
@ -904,7 +905,7 @@ public void SQL_InsertUser_Callback(Database db, DBResultSet results, const char
|
||||
{
|
||||
int client = GetClientFromSerial(data);
|
||||
|
||||
if(!client)
|
||||
if(client == 0)
|
||||
{
|
||||
LogError("Timer error! Failed to insert a disconnected player's data to the table. Reason: %s", error);
|
||||
}
|
||||
@ -973,8 +974,12 @@ public void SQL_DBConnect()
|
||||
// support unicode names
|
||||
gH_SQL.SetCharset("utf8");
|
||||
|
||||
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 `%susers` (`auth` VARCHAR(32) NOT NULL, `name` VARCHAR(32), `country` VARCHAR(128), `ip` VARCHAR(64), PRIMARY KEY (`auth`));", gS_MySQLPrefix);
|
||||
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");
|
||||
|
||||
// CREATE TABLE IF NOT EXISTS
|
||||
gH_SQL.Query(SQL_CreateTable_Callback, sQuery);
|
||||
@ -988,6 +993,30 @@ public void SQL_CreateTable_Callback(Database db, DBResultSet results, const cha
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public void SQL_TableMigration1_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? "(`lastlogin` INT NOT NULL DEFAULT -1)":"COLUMN `lastlogin` INTEGER NOT NULL DEFAULT -1");
|
||||
gH_SQL.Query(SQL_AlterTable1_Callback, sQuery);
|
||||
}
|
||||
}
|
||||
|
||||
public void SQL_AlterTable1_Callback(Database db, DBResultSet results, const char[] error, any data)
|
||||
{
|
||||
if(results == null)
|
||||
{
|
||||
LogError("Timer error! Table alteration 1 (core) failed. Reason: %s", error);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void PreThink(int client)
|
||||
|
||||
@ -65,6 +65,9 @@ bool gB_MySQL = false;
|
||||
// table prefix
|
||||
char gS_MySQLPrefix[32];
|
||||
|
||||
// modules
|
||||
bool gB_Stats = false;
|
||||
|
||||
public Plugin myinfo =
|
||||
{
|
||||
name = "[shavit] Rankings",
|
||||
@ -137,6 +140,25 @@ public void OnPluginStart()
|
||||
gCV_TopAmount = CreateConVar("shavit_rankings_topamount", "100", "Amount of people to show within the sm_top menu.", 0, true, 1.0, false);
|
||||
|
||||
AutoExecConfig();
|
||||
|
||||
// modules
|
||||
gB_Stats = LibraryExists("shavit-stats");
|
||||
}
|
||||
|
||||
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)
|
||||
@ -382,7 +404,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 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 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);
|
||||
|
||||
gH_SQL.Query(SQL_ShowTopMenu_Callback, sQuery, GetClientSerial(client));
|
||||
|
||||
@ -423,8 +445,6 @@ public void SQL_ShowTopMenu_Callback(Database db, DBResultSet results, const cha
|
||||
results.FetchString(0, sName, MAX_NAME_LENGTH);
|
||||
|
||||
int iRank = ++count;
|
||||
char[] sRank = new char[6];
|
||||
IntToString(iRank, sRank, 6); // info string for future purposes
|
||||
|
||||
char[] sDisplay = new char[64];
|
||||
|
||||
@ -441,7 +461,10 @@ public void SQL_ShowTopMenu_Callback(Database db, DBResultSet results, const cha
|
||||
FormatEx(sDisplay, 64, "#%d - %s (%.02f points)", iRank, sName, results.FetchFloat(1));
|
||||
}
|
||||
|
||||
m.AddItem(sRank, sDisplay);
|
||||
char[] sAuthID = new char[32];
|
||||
results.FetchString(2, sAuthID, 32);
|
||||
|
||||
m.AddItem(sAuthID, sDisplay);
|
||||
}
|
||||
}
|
||||
|
||||
@ -452,13 +475,23 @@ public void SQL_ShowTopMenu_Callback(Database db, DBResultSet results, const cha
|
||||
|
||||
public int MenuHandler_TopMenu(Menu m, MenuAction action, int param1, int param2)
|
||||
{
|
||||
// *eventually* add some shavit-stats call here, to show the player's profile
|
||||
if(action == MenuAction_End)
|
||||
{
|
||||
delete m;
|
||||
}
|
||||
if(action == MenuAction_Select && gB_Stats)
|
||||
{
|
||||
char[] sInfo = new char[32];
|
||||
m.GetItem(param2, sInfo, 32);
|
||||
|
||||
return 0;
|
||||
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)
|
||||
|
||||
@ -47,11 +47,10 @@ char gS_MySQLPrefix[32];
|
||||
|
||||
// cache
|
||||
int gI_MapType[MAXPLAYERS+1];
|
||||
int gI_Target[MAXPLAYERS+1];
|
||||
BhopStyle gBS_Style[MAXPLAYERS+1];
|
||||
char gS_TargetAuth[MAXPLAYERS+1][32];
|
||||
char gS_TargetName[MAXPLAYERS+1][MAX_NAME_LENGTH];
|
||||
int gI_WRAmount[MAXPLAYERS+1];
|
||||
int gI_ClearCount[MAXPLAYERS+1];
|
||||
int gI_TotalMaps = 0;
|
||||
|
||||
// cvars
|
||||
ConVar gCV_MVPRankOnes = null;
|
||||
@ -65,6 +64,17 @@ public Plugin myinfo =
|
||||
url = "https://github.com/shavitush/bhoptimer"
|
||||
}
|
||||
|
||||
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
|
||||
{
|
||||
// natives
|
||||
CreateNative("Shavit_OpenStatsMenu", Native_OpenStatsMenu);
|
||||
CreateNative("Shavit_GetWRCount", Native_GetWRConut);
|
||||
|
||||
RegPluginLibrary("shavit-stats");
|
||||
|
||||
return APLRes_Success;
|
||||
}
|
||||
|
||||
public void OnAllPluginsLoaded()
|
||||
{
|
||||
if(!LibraryExists("shavit-wr"))
|
||||
@ -99,29 +109,6 @@ public void OnPluginStart()
|
||||
SetSQLInfo();
|
||||
}
|
||||
|
||||
public void OnMapStart()
|
||||
{
|
||||
char[] sQuery = new char[256];
|
||||
FormatEx(sQuery, 256, "SELECT COUNT(*) FROM (SELECT id FROM %smapzones GROUP BY map) s;", gS_MySQLPrefix);
|
||||
|
||||
gH_SQL.Query(SQL_GetTotalMaps_Callback, sQuery);
|
||||
}
|
||||
|
||||
public void SQL_GetTotalMaps_Callback(Database db, DBResultSet results, const char[] error, any data)
|
||||
{
|
||||
if(results == null)
|
||||
{
|
||||
LogError("Timer (get total maps) SQL query failed. You might be missing shavit-zones. Reason: %s", error);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(results.FetchRow())
|
||||
{
|
||||
gI_TotalMaps = results.FetchInt(0);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnClientPutInServer(int client)
|
||||
{
|
||||
gI_WRAmount[client] = 0;
|
||||
@ -195,8 +182,7 @@ public void SQL_SetPrefix()
|
||||
|
||||
public void Player_Event(Event event, const char[] name, bool dontBroadcast)
|
||||
{
|
||||
int userid = event.GetInt("userid");
|
||||
int client = GetClientOfUserId(userid);
|
||||
int client = GetClientOfUserId(event.GetInt("userid"));
|
||||
|
||||
if(IsValidClient(client))
|
||||
{
|
||||
@ -245,9 +231,6 @@ public void UpdateWRs(int client)
|
||||
}
|
||||
|
||||
gH_SQL.Query(SQL_GetWRs_Callback, sQuery, GetClientSerial(client));
|
||||
|
||||
FormatEx(sQuery, 256, "SELECT COUNT(*) FROM (SELECT id FROM %splayertimes WHERE auth = '%s' GROUP BY map) s LIMIT 1;", gS_MySQLPrefix, sAuthID);
|
||||
gH_SQL.Query(SQL_GetClears_Callback, sQuery, GetClientSerial(client));
|
||||
}
|
||||
}
|
||||
|
||||
@ -277,28 +260,6 @@ public void SQL_GetWRs_Callback(Database db, DBResultSet results, const char[] e
|
||||
gI_WRAmount[client] = iWRs;
|
||||
}
|
||||
|
||||
public void SQL_GetClears_Callback(Database db, DBResultSet results, const char[] error, any data)
|
||||
{
|
||||
if(results == null)
|
||||
{
|
||||
LogError("Timer (get clear amount) SQL query failed. Reason: %s", error);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int client = GetClientFromSerial(data);
|
||||
|
||||
if(client == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(results.FetchRow())
|
||||
{
|
||||
gI_ClearCount[client] = results.FetchInt(0);
|
||||
}
|
||||
}
|
||||
|
||||
public Action Command_Profile(int client, int args)
|
||||
{
|
||||
if(!IsValidClient(client))
|
||||
@ -321,82 +282,141 @@ public Action Command_Profile(int client, int args)
|
||||
}
|
||||
}
|
||||
|
||||
gI_Target[client] = target;
|
||||
GetClientAuthId(target, AuthId_Steam3, gS_TargetAuth[client], 32);
|
||||
|
||||
return ShowStyleMenu(client);
|
||||
return OpenStatsMenu(client, gS_TargetAuth[client]);
|
||||
}
|
||||
|
||||
public Action ShowStyleMenu(int client)
|
||||
public Action OpenStatsMenu(int client, const char[] authid)
|
||||
{
|
||||
if(!IsValidClient(client))
|
||||
{
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
if(!IsValidClient(gI_Target[client]))
|
||||
{
|
||||
Shavit_PrintToChat(client, "The target has disconnected.");
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
char[] sAuthID = new char[32];
|
||||
GetClientAuthId(gI_Target[client], AuthId_Steam3, sAuthID, 32);
|
||||
|
||||
char[] sRankingString = new char[128];
|
||||
// big ass query, looking for optimizations
|
||||
char[] sQuery = new char[2048];
|
||||
|
||||
if(gB_Rankings)
|
||||
{
|
||||
FormatEx(sRankingString, 128, "\nRank: %d/%d\nPoints: %d", Shavit_GetRank(gI_Target[client]), Shavit_GetRankedPlayers(), RoundToFloor(Shavit_GetPoints(gI_Target[client])));
|
||||
FormatEx(sQuery, 2048, "SELECT a.clears, b.maps, c.wrs, d.name, d.country, d.lastlogin, e.rank, f.points 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);
|
||||
}
|
||||
|
||||
char[] sCountry = new char[64];
|
||||
GetClientIP(gI_Target[client], sCountry, 64);
|
||||
|
||||
if(!GeoipCountry(sCountry, sCountry, 64))
|
||||
else
|
||||
{
|
||||
strcopy(sCountry, 64, "Local Area Network");
|
||||
FormatEx(sQuery, 2048, "SELECT a.clears, b.maps, c.wrs, d.name, d.country, d.lastlogin 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 " ...
|
||||
"LIMIT 1;", gS_MySQLPrefix, authid, gS_MySQLPrefix, gS_MySQLPrefix, authid, gS_MySQLPrefix, authid);
|
||||
}
|
||||
|
||||
char[] sClearString = new char[128];
|
||||
FormatEx(sClearString, 128, "Map completions: %d/%d (%.01f%%)", gI_ClearCount[gI_Target[client]], gI_TotalMaps, ((float((gI_ClearCount[gI_Target[client]])) / gI_TotalMaps) * 100.0));
|
||||
|
||||
Menu m = new Menu(MenuHandler_ProfileHandler);
|
||||
m.SetTitle("%N's profile.\nCountry: %s\n%s\n%s #1 records: %d%s\nSteamID3: %s", gI_Target[client], sCountry, sClearString, (gCV_MVPRankOnes.IntValue == 2)? gS_BhopStyles[0]:"Total", gI_WRAmount[gI_Target[client]], sRankingString, sAuthID);
|
||||
|
||||
for(int i = 0; i < sizeof(gS_BhopStyles); i++)
|
||||
{
|
||||
if(!(gI_StyleProperties[i] & STYLE_UNRANKED))
|
||||
{
|
||||
char[] sInfo = new char[4];
|
||||
IntToString(i, sInfo, 4);
|
||||
|
||||
m.AddItem(sInfo, gS_BhopStyles[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// should NEVER happen
|
||||
if(m.ItemCount == 0)
|
||||
{
|
||||
m.AddItem("-1", "Nothing");
|
||||
}
|
||||
|
||||
m.ExitButton = true;
|
||||
|
||||
m.Display(client, 20);
|
||||
gH_SQL.Query(OpenStatsMenuCallback, sQuery, GetClientSerial(client));
|
||||
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
public void OpenStatsMenuCallback(Database db, DBResultSet results, const char[] error, any data)
|
||||
{
|
||||
if(results == null)
|
||||
{
|
||||
LogError("Timer (statsmenu) SQL query failed. Reason: %s", error);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
int client = GetClientFromSerial(data);
|
||||
|
||||
if(client == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(results.FetchRow())
|
||||
{
|
||||
// create variables
|
||||
int iClears = results.FetchInt(0);
|
||||
int iTotalMaps = results.FetchInt(1);
|
||||
int iWRs = results.FetchInt(2);
|
||||
results.FetchString(3, gS_TargetName[client], MAX_NAME_LENGTH);
|
||||
|
||||
char[] sCountry = new char[64];
|
||||
results.FetchString(4, sCountry, 64);
|
||||
|
||||
int iLastLogin = results.FetchInt(5);
|
||||
char[] sLastLogin = new char[32];
|
||||
FormatTime(sLastLogin, 32, "%Y-%m-%d %H:%M:%S", iLastLogin);
|
||||
Format(sLastLogin, 32, "Last login: %s", (iLastLogin != -1)? sLastLogin:"N/A");
|
||||
|
||||
int iRank = -1;
|
||||
float fPoints = -1.0;
|
||||
|
||||
if(gB_Rankings)
|
||||
{
|
||||
iRank = results.FetchInt(6);
|
||||
fPoints = results.FetchFloat(7);
|
||||
}
|
||||
|
||||
char[] sRankingString = new char[64];
|
||||
|
||||
if(gB_Rankings)
|
||||
{
|
||||
if(iRank > 0 && fPoints > 0.0)
|
||||
{
|
||||
FormatEx(sRankingString, 64, "\nRank: #%d/%d\nPoints: %.02f", iRank, Shavit_GetRankedPlayers(), fPoints);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
FormatEx(sRankingString, 64, "\nRank: Unranked");
|
||||
}
|
||||
}
|
||||
|
||||
if(iClears > iTotalMaps)
|
||||
{
|
||||
iClears = iTotalMaps;
|
||||
}
|
||||
|
||||
char[] sClearString = new char[128];
|
||||
FormatEx(sClearString, 128, "Map completions: %d/%d (%.01f%%)", iClears, iTotalMaps, ((float(iClears) / iTotalMaps) * 100.0));
|
||||
|
||||
Menu m = new Menu(MenuHandler_ProfileHandler);
|
||||
m.SetTitle("%s's profile. %s\nCountry: %s\n%s\n%s\n[%s] world records: %d%s\n", gS_TargetName[client], gS_TargetAuth[client], sCountry, sLastLogin, sClearString, gS_BhopStyles[0], iWRs, sRankingString);
|
||||
|
||||
for(int i = 0; i < sizeof(gS_BhopStyles); i++)
|
||||
{
|
||||
if(!(gI_StyleProperties[i] & STYLE_UNRANKED))
|
||||
{
|
||||
char[] sInfo = new char[4];
|
||||
IntToString(i, sInfo, 4);
|
||||
|
||||
m.AddItem(sInfo, gS_BhopStyles[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// should NEVER happen
|
||||
if(m.ItemCount == 0)
|
||||
{
|
||||
m.AddItem("-1", "Nothing");
|
||||
}
|
||||
|
||||
m.ExitButton = true;
|
||||
m.Display(client, 20);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Shavit_PrintToChat(client, "ERROR: Could not open the stats menu.");
|
||||
}
|
||||
}
|
||||
|
||||
public int MenuHandler_ProfileHandler(Menu m, MenuAction action, int param1, int param2)
|
||||
{
|
||||
if(action == MenuAction_Select)
|
||||
{
|
||||
if(!IsValidClient(gI_Target[param1]))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
char[] sInfo = new char[32];
|
||||
m.GetItem(param2, sInfo, 32);
|
||||
|
||||
@ -424,11 +444,6 @@ public int MenuHandler_TypeHandler(Menu m, MenuAction action, int param1, int pa
|
||||
{
|
||||
if(action == MenuAction_Select)
|
||||
{
|
||||
if(!IsValidClient(gI_Target[param1]))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
char[] sInfo = new char[32];
|
||||
m.GetItem(param2, sInfo, 32);
|
||||
gI_MapType[param1] = StringToInt(sInfo);
|
||||
@ -438,7 +453,7 @@ public int MenuHandler_TypeHandler(Menu m, MenuAction action, int param1, int pa
|
||||
|
||||
else if(action == MenuAction_Cancel && param2 == MenuCancel_ExitBack)
|
||||
{
|
||||
ShowStyleMenu(param1);
|
||||
OpenStatsMenu(param1, gS_TargetAuth[param1]);
|
||||
}
|
||||
|
||||
else if(action == MenuAction_End)
|
||||
@ -465,11 +480,6 @@ public Action Timer_DBFailure(Handle timer, any data)
|
||||
|
||||
public void ShowMaps(int client)
|
||||
{
|
||||
if(!IsValidClient(gI_Target[client]))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// database not found, display with a 3 seconds delay
|
||||
if(gH_SQL == null)
|
||||
{
|
||||
@ -478,19 +488,16 @@ public void ShowMaps(int client)
|
||||
return;
|
||||
}
|
||||
|
||||
char[] sAuth = new char[32];
|
||||
GetClientAuthId(gI_Target[client], AuthId_Steam3, sAuth, 32);
|
||||
|
||||
char[] sQuery = new char[512];
|
||||
|
||||
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, sAuth, view_as<int>(gBS_Style[client]));
|
||||
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]));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
FormatEx(sQuery, 512, "SELECT DISTINCT m.map FROM %smapzones m LEFT JOIN %splayertimes r ON r.map = m.map AND r.auth = '%s' AND r.style = %d WHERE r.map IS NULL ORDER BY m.map;", gS_MySQLPrefix, gS_MySQLPrefix, sAuth, view_as<int>(gBS_Style[client]));
|
||||
FormatEx(sQuery, 512, "SELECT DISTINCT m.map FROM %smapzones m LEFT JOIN %splayertimes r ON r.map = m.map AND r.auth = '%s' AND r.style = %d WHERE r.map IS NULL ORDER BY m.map;", gS_MySQLPrefix, gS_MySQLPrefix, gS_TargetAuth[client], view_as<int>(gBS_Style[client]));
|
||||
}
|
||||
|
||||
gH_SQL.Query(ShowMapsCallback, sQuery, GetClientSerial(client), DBPrio_High);
|
||||
@ -507,7 +514,7 @@ public void ShowMapsCallback(Database db, DBResultSet results, const char[] erro
|
||||
|
||||
int client = GetClientFromSerial(data);
|
||||
|
||||
if(!IsValidClient(client) || !IsValidClient(gI_Target[client]))
|
||||
if(client == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@ -518,12 +525,12 @@ public void ShowMapsCallback(Database db, DBResultSet results, const char[] erro
|
||||
|
||||
if(gI_MapType[client] == MAPSDONE)
|
||||
{
|
||||
FormatEx(sTitle, 64, "[%s] Maps done for %N: (%d)", gS_ShortBhopStyles[gBS_Style[client]], gI_Target[client], rows);
|
||||
FormatEx(sTitle, 64, "[%s] Maps done for %s: (%d)", gS_ShortBhopStyles[gBS_Style[client]], gS_TargetName[client], rows);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
FormatEx(sTitle, 64, "[%s] Maps left for %N: (%d)", gS_ShortBhopStyles[gBS_Style[client]], gI_Target[client], rows);
|
||||
FormatEx(sTitle, 64, "[%s] Maps left for %s: (%d)", gS_ShortBhopStyles[gBS_Style[client]], gS_TargetName[client], rows);
|
||||
}
|
||||
|
||||
Menu m = new Menu(MenuHandler_ShowMaps);
|
||||
@ -599,7 +606,7 @@ public int MenuHandler_ShowMaps(Menu m, MenuAction action, int param1, int param
|
||||
|
||||
if(StrEqual(sInfo, "nope"))
|
||||
{
|
||||
ShowStyleMenu(param1);
|
||||
OpenStatsMenu(param1, gS_TargetAuth[param1]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -612,7 +619,7 @@ public int MenuHandler_ShowMaps(Menu m, MenuAction action, int param1, int param
|
||||
|
||||
else if(action == MenuAction_Cancel && param2 == MenuCancel_ExitBack)
|
||||
{
|
||||
ShowStyleMenu(param1);
|
||||
OpenStatsMenu(param1, gS_TargetAuth[param1]);
|
||||
}
|
||||
|
||||
else if(action == MenuAction_End)
|
||||
@ -705,7 +712,7 @@ public void SQL_SubMenu_Callback(Database db, DBResultSet results, const char[]
|
||||
|
||||
if(iJumps > 0 || iStrafes > 0)
|
||||
{
|
||||
FormatEx(sDisplay, 128, (fSync != -1.0)? "Strafes: %d (%.02f%%)":"Strafes: %d", iStrafes, fSync);
|
||||
FormatEx(sDisplay, 128, (fSync > 0.0)? "Strafes: %d (%.02f%%)":"Strafes: %d", iStrafes, fSync);
|
||||
m.AddItem("-1", sDisplay);
|
||||
}
|
||||
|
||||
@ -718,7 +725,6 @@ public void SQL_SubMenu_Callback(Database db, DBResultSet results, const char[]
|
||||
m.SetTitle(sFormattedTitle);
|
||||
|
||||
m.ExitBackButton = true;
|
||||
|
||||
m.Display(client, 20);
|
||||
}
|
||||
|
||||
@ -736,3 +742,16 @@ public int SubMenu_Handler(Menu m, MenuAction action, int param1, int param2)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int Native_OpenStatsMenu(Handle handler, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
GetNativeString(2, gS_TargetAuth[client], 32);
|
||||
|
||||
OpenStatsMenu(client, gS_TargetAuth[client]);
|
||||
}
|
||||
|
||||
public int Native_GetWRConut(Handle handler, int numParams)
|
||||
{
|
||||
return gI_WRAmount[GetNativeCell(1)];
|
||||
}
|
||||
|
||||
@ -35,6 +35,7 @@
|
||||
|
||||
bool gB_Late = false;
|
||||
bool gB_Rankings = false;
|
||||
bool gB_Stats = false;
|
||||
|
||||
// forwards
|
||||
Handle gH_OnWorldRecord = null;
|
||||
@ -104,12 +105,6 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max
|
||||
return APLRes_Success;
|
||||
}
|
||||
|
||||
public void OnAllPluginsLoaded()
|
||||
{
|
||||
// modules
|
||||
gB_Rankings = LibraryExists("shavit-rankings");
|
||||
}
|
||||
|
||||
public void OnPluginStart()
|
||||
{
|
||||
// debug because I was making this all by myself and no one wanted to help me *sniff*
|
||||
@ -159,6 +154,10 @@ public void OnPluginStart()
|
||||
strcopy(gS_Color_Better, 16, (evType == Engine_CSS)? "\x07AD3BA6":"\x0C");
|
||||
strcopy(gS_Color_Worse, 16, (evType == Engine_CSS)? "\x07CCCCCC":"\x08");
|
||||
|
||||
// modules
|
||||
gB_Rankings = LibraryExists("shavit-rankings");
|
||||
gB_Stats = LibraryExists("shavit-stats");
|
||||
|
||||
// mysql
|
||||
Shavit_GetDB(gH_SQL);
|
||||
SQL_SetPrefix();
|
||||
@ -240,6 +239,11 @@ public void OnLibraryAdded(const char[] name)
|
||||
{
|
||||
gB_Rankings = true;
|
||||
}
|
||||
|
||||
else if(StrEqual(name, "shavit-stats"))
|
||||
{
|
||||
gB_Stats = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnLibraryRemoved(const char[] name)
|
||||
@ -254,6 +258,11 @@ public void OnLibraryRemoved(const char[] name)
|
||||
gB_Rankings = false;
|
||||
}
|
||||
|
||||
else if(StrEqual(name, "shavit-stats"))
|
||||
{
|
||||
gB_Stats = false;
|
||||
}
|
||||
|
||||
else if(StrEqual(name, "adminmenu"))
|
||||
{
|
||||
gH_AdminMenu = null;
|
||||
@ -626,13 +635,12 @@ public void SQL_OpenDelete_Callback(Database db, DBResultSet results, const char
|
||||
m.AddItem(sID, sDisplay);
|
||||
}
|
||||
|
||||
if(!iCount)
|
||||
if(iCount == 0)
|
||||
{
|
||||
m.AddItem("-1", "No records found.");
|
||||
}
|
||||
|
||||
m.ExitButton = true;
|
||||
|
||||
m.Display(client, 20);
|
||||
}
|
||||
|
||||
@ -981,7 +989,6 @@ public void SQL_WR_Callback(Database db, DBResultSet results, const char[] error
|
||||
}
|
||||
|
||||
m.ExitBackButton = true;
|
||||
|
||||
m.Display(client, 20);
|
||||
}
|
||||
|
||||
@ -989,11 +996,19 @@ public int WRMenu_Handler(Menu m, MenuAction action, int param1, int param2)
|
||||
{
|
||||
if(action == MenuAction_Select)
|
||||
{
|
||||
char[] info = new char[16];
|
||||
m.GetItem(param2, info, 16);
|
||||
int id = StringToInt(info);
|
||||
char[] sInfo = new char[16];
|
||||
m.GetItem(param2, sInfo, 16);
|
||||
int id = StringToInt(sInfo);
|
||||
|
||||
OpenSubMenu(param1, id);
|
||||
if(id != -1)
|
||||
{
|
||||
OpenSubMenu(param1, id);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
ShowWRStyleMenu(param1, gS_ClientMap[param1]);
|
||||
}
|
||||
}
|
||||
|
||||
else if(action == MenuAction_Cancel && param2 == MenuCancel_ExitBack)
|
||||
@ -1106,12 +1121,20 @@ public int RRMenu_Handler(Menu m, MenuAction action, int param1, int param2)
|
||||
char[] sInfo = new char[192];
|
||||
m.GetItem(param2, sInfo, 192);
|
||||
|
||||
char[][] sExploded = new char[2][192];
|
||||
ExplodeString(sInfo, ";", sExploded, 2, 192, true);
|
||||
if(StringToInt(sInfo) != -1)
|
||||
{
|
||||
char[][] sExploded = new char[2][192];
|
||||
ExplodeString(sInfo, ";", sExploded, 2, 192, true);
|
||||
|
||||
strcopy(gS_ClientMap[param1], 192, sExploded[1]);
|
||||
strcopy(gS_ClientMap[param1], 192, sExploded[1]);
|
||||
|
||||
OpenSubMenu(param1, StringToInt(sExploded[0]));
|
||||
OpenSubMenu(param1, StringToInt(sExploded[0]));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
ShowWRStyleMenu(param1, gS_ClientMap[param1]);
|
||||
}
|
||||
}
|
||||
|
||||
else if(action == MenuAction_Cancel && param2 == MenuCancel_ExitBack)
|
||||
@ -1223,6 +1246,8 @@ public void SQL_SubMenu_Callback(Database db, DBResultSet results, const char[]
|
||||
FormatEx(sDisplay, 128, (fSync != -1.0)? "Strafes: %d (%.02f%%)":"Strafes: %d", iStrafes, fSync);
|
||||
m.AddItem("-1", sDisplay);
|
||||
}
|
||||
|
||||
m.AddItem(sAuthID, "Player stats");
|
||||
}
|
||||
|
||||
else
|
||||
@ -1247,7 +1272,23 @@ public void SQL_SubMenu_Callback(Database db, DBResultSet results, const char[]
|
||||
|
||||
public int SubMenu_Handler(Menu m, MenuAction action, int param1, int param2)
|
||||
{
|
||||
if((action == MenuAction_Cancel && param2 == MenuCancel_ExitBack) || action == MenuAction_Select)
|
||||
if(action == MenuAction_Select)
|
||||
{
|
||||
char[] sInfo = new char[32];
|
||||
m.GetItem(param2, sInfo, 32);
|
||||
|
||||
if(gB_Stats && StringToInt(sInfo) != -1)
|
||||
{
|
||||
Shavit_OpenStatsMenu(param1, sInfo);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
StartWRMenu(param1, gS_ClientMap[param1], view_as<int>(gBS_LastWR[param1]));
|
||||
}
|
||||
}
|
||||
|
||||
else if(action == MenuAction_Cancel && param2 == MenuCancel_ExitBack)
|
||||
{
|
||||
StartWRMenu(param1, gS_ClientMap[param1], view_as<int>(gBS_LastWR[param1]));
|
||||
}
|
||||
|
||||
@ -297,9 +297,7 @@ public int Native_InsideZone(Handle handler, int numParams)
|
||||
|
||||
public int Native_IsClientCreatingZone(Handle handler, int numParams)
|
||||
{
|
||||
int client = GetNativeCell(1);
|
||||
|
||||
return (gI_MapStep[client] != 0);
|
||||
return (gI_MapStep[GetNativeCell(1)] != 0);
|
||||
}
|
||||
|
||||
public void SetupColors()
|
||||
|
||||
Loading…
Reference in New Issue
Block a user