From 3c0f2a857f95c0cae5a32abf77b73f5413247670 Mon Sep 17 00:00:00 2001 From: shavitush Date: Fri, 5 Aug 2016 05:13:23 +0300 Subject: [PATCH] huge rework on shavit-stats and add 'last login' (#149) --- README.md | 9 ++ scripting/include/shavit.inc | 21 +++ scripting/shavit-chat.sp | 2 +- scripting/shavit-core.sp | 35 ++++- scripting/shavit-rankings.sp | 53 +++++-- scripting/shavit-stats.sp | 283 +++++++++++++++++++---------------- scripting/shavit-wr.sp | 77 +++++++--- scripting/shavit-zones.sp | 4 +- 8 files changed, 317 insertions(+), 167 deletions(-) diff --git a/README.md b/README.md index 5b09a589..1495e2f9 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/scripting/include/shavit.inc b/scripting/include/shavit.inc index 614fa740..e49f5ef8 100644 --- a/scripting/include/shavit.inc +++ b/scripting/include/shavit.inc @@ -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"); diff --git a/scripting/shavit-chat.sp b/scripting/shavit-chat.sp index e2666e2f..f3e2acb1 100644 --- a/scripting/shavit-chat.sp +++ b/scripting/shavit-chat.sp @@ -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]); } diff --git a/scripting/shavit-core.sp b/scripting/shavit-core.sp index b1281b96..122816cb 100644 --- a/scripting/shavit-core.sp +++ b/scripting/shavit-core.sp @@ -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) diff --git a/scripting/shavit-rankings.sp b/scripting/shavit-rankings.sp index a6ca99ee..23c39a41 100644 --- a/scripting/shavit-rankings.sp +++ b/scripting/shavit-rankings.sp @@ -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) diff --git a/scripting/shavit-stats.sp b/scripting/shavit-stats.sp index bdb8b06f..a4cf986d 100644 --- a/scripting/shavit-stats.sp +++ b/scripting/shavit-stats.sp @@ -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(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(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(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(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)]; +} diff --git a/scripting/shavit-wr.sp b/scripting/shavit-wr.sp index a7b20543..f14ec8be 100644 --- a/scripting/shavit-wr.sp +++ b/scripting/shavit-wr.sp @@ -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(gBS_LastWR[param1])); + } + } + + else if(action == MenuAction_Cancel && param2 == MenuCancel_ExitBack) { StartWRMenu(param1, gS_ClientMap[param1], view_as(gBS_LastWR[param1])); } diff --git a/scripting/shavit-zones.sp b/scripting/shavit-zones.sp index 0fb0b5be..fcde88e8 100644 --- a/scripting/shavit-zones.sp +++ b/scripting/shavit-zones.sp @@ -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()