diff --git a/addons/sourcemod/scripting/include/shavit.inc b/addons/sourcemod/scripting/include/shavit.inc index 3cdbcb10..b38e1533 100644 --- a/addons/sourcemod/scripting/include/shavit.inc +++ b/addons/sourcemod/scripting/include/shavit.inc @@ -44,7 +44,7 @@ #define HUD_NOSOUNDS (1 << 11) // disables sounds on personal best, world record etc #define HUD_NOPRACALERT (1 << 12) // hides practice mode chat alert -#define SHAVIT_LOG_QUERIES 0 +#define SHAVIT_LOG_QUERIES 1 // status enum TimerStatus diff --git a/addons/sourcemod/scripting/include/shavit/sql-create-tables-and-migrations.sp b/addons/sourcemod/scripting/include/shavit/sql-create-tables-and-migrations.sp index 6f50b52e..dcae8b69 100644 --- a/addons/sourcemod/scripting/include/shavit/sql-create-tables-and-migrations.sp +++ b/addons/sourcemod/scripting/include/shavit/sql-create-tables-and-migrations.sp @@ -166,14 +166,15 @@ public void SQL_CreateTables(Database2 hSQL, const char[] prefix, bool mysql) if (gB_MySQL) { FormatEx(sQuery, sizeof(sQuery), - "CREATE TABLE IF NOT EXISTS `%splayertimes` (`id` INT NOT NULL AUTO_INCREMENT, `auth` INT NOT NULL, `map` VARCHAR(255) NOT NULL, `time` FLOAT NOT NULL, `jumps` INT, `style` TINYINT NOT NULL DEFAULT 0, `date` INT, `strafes` INT, `sync` FLOAT, `points` FLOAT NOT NULL DEFAULT 0, `track` TINYINT NOT NULL DEFAULT 0, `perfs` FLOAT DEFAULT 0, `completions` SMALLINT DEFAULT 1, `exact_time_int` INT DEFAULT 0, `points_calced_from` FLOAT NOT NULL DEFAULT 0, PRIMARY KEY (`id`), INDEX `map` (`map`, `style`, `track`, `time`), INDEX `auth` (`auth`, `date`, `points`), INDEX `time` (`time`)) ENGINE=INNODB;", - gS_SQLPrefix, gS_SQLPrefix, gS_SQLPrefix); + "CREATE TABLE IF NOT EXISTS `%splayertimes` (`id` INT NOT NULL AUTO_INCREMENT, `style` TINYINT NOT NULL DEFAULT 0, `track` TINYINT NOT NULL DEFAULT 0, `time` FLOAT NOT NULL, `auth` INT NOT NULL, `map` VARCHAR(255) NOT NULL, `points` FLOAT NOT NULL DEFAULT 0, `points_calced_from` FLOAT NOT NULL DEFAULT 0, `exact_time_int` INT DEFAULT 0, `jumps` INT, `date` INT, `strafes` INT, `sync` FLOAT, `perfs` FLOAT DEFAULT 0, `completions` SMALLINT DEFAULT 1, PRIMARY KEY (`id`), INDEX `map` (`map`, `style`, `track`, `time`), INDEX `auth` (`auth`, `date`, `points`), INDEX `time` (`time`)) ENGINE=INNODB;", + gS_SQLPrefix); } else { + // id style track time auth map points points_calced_from exact_time_int FormatEx(sQuery, sizeof(sQuery), - "CREATE TABLE IF NOT EXISTS `%splayertimes` (`id` INTEGER PRIMARY KEY, `auth` INT NOT NULL, `map` VARCHAR(255) NOT NULL, `time` FLOAT NOT NULL, `jumps` INT, `style` TINYINT NOT NULL DEFAULT 0, `date` INT, `strafes` INT, `sync` FLOAT, `points` FLOAT NOT NULL DEFAULT 0, `track` TINYINT NOT NULL DEFAULT 0, `perfs` FLOAT DEFAULT 0, `completions` SMALLINT DEFAULT 1, `exact_time_int` INT DEFAULT 0, `points_calced_from` FLOAT NOT NULL DEFAULT 0);", - gS_SQLPrefix, gS_SQLPrefix, gS_SQLPrefix); + "CREATE TABLE IF NOT EXISTS `%splayertimes` (`id` INTEGER PRIMARY KEY, `style` TINYINT NOT NULL DEFAULT 0, `track` TINYINT NOT NULL DEFAULT 0, `time` FLOAT NOT NULL, `auth` INT NOT NULL, `map` VARCHAR(255) NOT NULL, `points` FLOAT NOT NULL DEFAULT 0, `points_calced_from` FLOAT NOT NULL DEFAULT 0, `exact_time_int` INT DEFAULT 0, `jumps` INT, `date` INT, `strafes` INT, `sync` FLOAT, `perfs` FLOAT DEFAULT 0, `completions` SMALLINT DEFAULT 1);", + gS_SQLPrefix); } hTrans.AddQuery(sQuery); @@ -391,7 +392,7 @@ void ApplyMigration_LowercaseMaps(const char[] table, int migration) void ApplyMigration_AddPlayertimesPointsCalcedFrom() { char sQuery[192]; - FormatEx(sQuery, 192, "ALTER TABLE `%splayertimes` ADD COLUMN `points_calced_from` FLOAT NOT NULL DEFAULT 0 AFTER `exact_time_int`;", gS_SQLPrefix); + FormatEx(sQuery, 192, "ALTER TABLE `%splayertimes` ADD COLUMN `points_calced_from` FLOAT NOT NULL DEFAULT 0 AFTER `points`;", gS_SQLPrefix); gH_SQL.Query(SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_AddPlayertimesPointsCalcedFrom, DBPrio_High); } diff --git a/addons/sourcemod/scripting/shavit-rankings.sp b/addons/sourcemod/scripting/shavit-rankings.sp index cbe5ca20..5693cf44 100644 --- a/addons/sourcemod/scripting/shavit-rankings.sp +++ b/addons/sourcemod/scripting/shavit-rankings.sp @@ -73,6 +73,7 @@ bool gB_HasSQLRANK = false; // whether the sql driver supports RANK() bool gB_Stats = false; bool gB_Late = false; bool gB_TierQueried = false; +bool gB_TierRetrieved = false; int gI_Tier = 1; // No floating numbers for tiers, sorry. @@ -103,6 +104,7 @@ Handle gH_Forwards_OnRankAssigned = null; chatstrings_t gS_ChatStrings; int gI_Styles = 0; +bool gB_InitialRecalcStarted = false; bool gB_WorldRecordsCached = false; bool gB_WRHolderTablesMade = false; bool gB_WRHoldersRefreshed = false; @@ -169,8 +171,8 @@ public void OnPluginStart() gCV_PointsPerTier = new Convar("shavit_rankings_pointspertier", "50.0", "Base points to use for per-tier scaling.\nRead the design idea to see how it works: https://github.com/shavitush/bhoptimer/issues/465", 0, true, 1.0); gCV_WeightingMultiplier = new Convar("shavit_rankings_weighting", "0.975", "Weighing multiplier. 1.0 to disable weighting.\nFormula: p[1] * this^0 + p[2] * this^1 + p[3] * this^2 + ... + p[n] * this^(n-1)\nRestart server to apply.", 0, true, 0.01, true, 1.0); - gCV_WeightingLimit = new Convar("shavit_rankings_weighting_limit", "0", "Limit the number of times retreived for calculating a player's weighted points to this number.\n0 = no limit\nFor reference, a weighting of 0.975 to the power of 200 is 0.00632299938 and results in pretty much nil points for any further weighted times.\nUnused when shavit_rankings_weighting is 1.0.\nYou probably won't need to change this unless you have hundreds of thousands of player times in your database.", 0, true, 0.0, false); - gCV_LastLoginRecalculate = new Convar("shavit_rankings_llrecalc", "10080", "Maximum amount of time (in minutes) since last login to recalculate points for a player.\nsm_recalcall does not respect this setting.\n0 - disabled, don't filter anyone", 0, true, 0.0); + gCV_WeightingLimit = new Convar("shavit_rankings_weighting_limit", "0", "Limit the number of times retreived for calculating a player's weighted points to this number.\n0 = no limit\nFor reference, a weighting of 0.975 to the power of 300 is 0.00050278777 and results in pretty much nil points for any further weighted times.\nUnused when shavit_rankings_weighting is 1.0.\nYou probably won't need to change this unless you have hundreds of thousands of player times in your database.", 0, true, 0.0, false); + gCV_LastLoginRecalculate = new Convar("shavit_rankings_llrecalc", "0", "Maximum amount of time (in minutes) since last login to recalculate points for a player.\nsm_recalcall does not respect this setting.\n0 - disabled, don't filter anyone", 0, true, 0.0); gCV_MVPRankOnes_Slow = new Convar("shavit_rankings_mvprankones_slow", "1", "Uses a slower but more featureful MVP counting system.\nEnables the WR Holder ranks & counts for every style & track.\nYou probably won't need to change this unless you have hundreds of thousands of player times in your database.", 0, true, 0.0, true, 1.0); gCV_MVPRankOnes = new Convar("shavit_rankings_mvprankones", "2", "Set the players' amount of MVPs to the amount of #1 times they have.\n0 - Disabled\n1 - Enabled, for all styles.\n2 - Enabled, for default style only.\n(CS:S/CS:GO only)", 0, true, 0.0, true, 2.0); gCV_MVPRankOnes_Main = new Convar("shavit_rankings_mvprankones_maintrack", "1", "If set to 0, all tracks will be counted for the MVP stars.\nOtherwise, only the main track will be checked.\n\nRequires \"shavit_stats_mvprankones\" set to 1 or above.\n(CS:S/CS:GO only)", 0, true, 0.0, true, 1.0); @@ -380,7 +382,7 @@ public void OnMapStart() } // do NOT keep running this more than once per map, as UpdateAllPoints() is called after this eventually and locks up the database while it is running - if(gB_TierQueried) + if (gB_TierQueried) { return; } @@ -427,10 +429,15 @@ public void SQL_FillTierCache_Callback(Database db, DBResultSet results, const c SortADTArray(gA_ValidMaps, Sort_Ascending, Sort_String); + gB_TierRetrieved = true; + if (gA_MapTiers.GetValue(gS_Map, gI_Tier)) { - RecalculateCurrentMap(); - UpdateAllPoints(); + if (gB_WorldRecordsCached && !gB_InitialRecalcStarted) + { + RecalculateCurrentMap(); + UpdateAllPoints(); + } } else { @@ -442,20 +449,29 @@ public void SQL_FillTierCache_Callback(Database db, DBResultSet results, const c public void OnMapEnd() { - gB_TierQueried = false; - gB_WRHoldersRefreshed = false; - gB_WorldRecordsCached = false; - // might be null if Shavit_OnDatabaseLoaded hasn't been called yet - if (gH_SQL != null) + if (gH_SQL != null && gB_TierRetrieved && gB_WorldRecordsCached) { RecalculateCurrentMap(); } + + gB_InitialRecalcStarted = false; + gB_TierQueried = false; + gB_TierRetrieved = false; + gB_WRHoldersRefreshed = false; + gB_WorldRecordsCached = false; } public void Shavit_OnWorldRecordsCached() { gB_WorldRecordsCached = true; + + if (gB_TierRetrieved && !gB_InitialRecalcStarted) + { + gB_InitialRecalcStarted = true; + RecalculateCurrentMap(); + UpdateAllPoints(); + } } void CS_SetMVPCount_Test(int client, int count) @@ -730,7 +746,7 @@ void FormatRecalculate(bool bUseCurrentMap, int track, int style, char[] sQuery, if (Shavit_GetStyleSettingBool(style, "unranked") || fMultiplier == 0.0) { FormatEx(sQuery, sQueryLen, - "UPDATE %splayertimes SET points = 0 WHERE style = %d AND track %c 0 %s%s%s;", + "UPDATE %splayertimes SET points = 0, points_calced_from = 0 WHERE style = %d AND track %c 0 %s%s%s;", gS_MySQLPrefix, style, (track > 0) ? '>' : '=', @@ -752,19 +768,17 @@ void FormatRecalculate(bool bUseCurrentMap, int track, int style, char[] sQuery, FormatEx(sQuery, sQueryLen, "UPDATE %splayertimes PT " ... - "SET PT.points = ( "... - " ((%f * %d) * 1.5) + (%f / 15.0)) " ... - "* (%f / PT.time) " ... - "* %f " ... - "WHERE PT.style = %d AND PT.track = 0 AND PT.map = '%s';", + "SET PT.points_calced_from = %f, " ... + " PT.points = " ... + " %f * (%f / PT.time) " ... + "WHERE PT.style = %d AND PT.track = 0 AND PT.map = '%s' AND PT.points_calced_from != %f;", gS_MySQLPrefix, - gCV_PointsPerTier.FloatValue, - gI_Tier, fWR, + (((fWR * gCV_PointsPerTier.FloatValue) * 1.5) + (fWR / 15.0)) * fMultiplier, fWR, - fMultiplier, style, - gS_Map + gS_Map, + fWR ); } else @@ -772,18 +786,18 @@ void FormatRecalculate(bool bUseCurrentMap, int track, int style, char[] sQuery, FormatEx(sQuery, sQueryLen, "UPDATE %splayertimes PT " ... "INNER JOIN %swrs WR ON " ... - " PT.track = WR.track AND PT.style = WR.style AND PT.map = WR.map " ... - "SET PT.points = ( "... - " ((%f * %d) * 1.5) + (WR.time / 15.0)) " ... + " PT.track = 0 AND PT.track = WR.track AND PT.style = %d AND PT.style = WR.style AND PT.map = '%s' AND PT.map = WR.map AND PT.points_calced_from != WR.time " ... + "SET PT.points_calced_from = WR.time, " ... + " PT.points = "... + " (%f + (WR.time / 15.0)) " ... " * (WR.time / PT.time) " ... " * %f " ... - "WHERE PT.style = %d AND PT.track = 0 AND PT.map = '%s';", + ";", gS_MySQLPrefix, gS_MySQLPrefix, - gCV_PointsPerTier.FloatValue, - gI_Tier, - fMultiplier, style, - gS_Map + gS_Map, + ((gCV_PointsPerTier.FloatValue * gI_Tier) * 1.5), + fMultiplier ); } } @@ -792,18 +806,18 @@ void FormatRecalculate(bool bUseCurrentMap, int track, int style, char[] sQuery, FormatEx(sQuery, sQueryLen, "UPDATE %splayertimes PT " ... "INNER JOIN %swrs WR ON " ... - " PT.track = WR.track AND PT.style = WR.style AND PT.map = WR.map " ... - "SET PT.points = ( "... - " ((%f * 1) * 1.5) + (WR.time / 15.0)) " ... + " PT.track > 0 AND PT.track = WR.track AND PT.style = %d AND PT.style = WR.style AND PT.map = '%s' AND PT.map = WR.map AND PT.points_calced_from != WR.time " ... + "SET PT.points_calced_from = WR.time, " ... + " PT.points = "... + " (%f + (WR.time / 15.0)) " ... " * (WR.time / PT.time) " ... " * %f " ... - " * 0.25 " ... - "WHERE PT.style = %d AND PT.track > 0 AND PT.map = '%s';", + ";", gS_MySQLPrefix, gS_MySQLPrefix, - gCV_PointsPerTier.FloatValue, - fMultiplier, style, - gS_Map + gS_Map, + ((gCV_PointsPerTier.FloatValue * 1) * 1.5), + fMultiplier * 0.25 ); } } @@ -812,11 +826,12 @@ void FormatRecalculate(bool bUseCurrentMap, int track, int style, char[] sQuery, FormatEx(sQuery, sQueryLen, "UPDATE %splayertimes PT " ... "INNER JOIN %swrs WR ON " ... - " PT.track = WR.track AND PT.style = WR.style AND PT.map = WR.map " ... + " PT.track = WR.track AND PT.style = WR.style AND PT.map = WR.map AND PT.points_calced_from != WR.time " ... "INNER JOIN %smaptiers MT ON " ... " PT.map = MT.map " ... - "SET PT.points = ( "... - " ((%f * MT.tier) * 1.5) + (WR.time / 15.0)) " ... + "SET PT.points_calced_from = WR.time, " ... + " PT.points = "... + " (((%f * MT.tier) * 1.5) + (WR.time / 15.0)) " ... "* (WR.time / PT.time) " ... "* %f %s " ... "WHERE PT.style = %d AND PT.track %c 0;", @@ -837,7 +852,7 @@ public Action Command_RecalcAll(int client, int args) Transaction2 trans = new Transaction2(); char sQuery[1024]; - FormatEx(sQuery, sizeof(sQuery), "UPDATE %splayertimes SET points = 0;", gS_MySQLPrefix); + FormatEx(sQuery, sizeof(sQuery), "UPDATE %splayertimes SET points = 0, points_calced_from = 0;", gS_MySQLPrefix); trans.AddQuery(sQuery); FormatEx(sQuery, sizeof(sQuery), "UPDATE %susers SET points = 0;", gS_MySQLPrefix); trans.AddQuery(sQuery); @@ -898,10 +913,13 @@ void RecalculateCurrentMap() for(int i = 0; i < gI_Styles; i++) { - FormatRecalculate(true, Track_Main, i, sQuery, sizeof(sQuery)); - gH_SQL_b.Query(SQL_Recalculate_Callback, sQuery, (i << 8) | 0, DBPrio_High); - FormatRecalculate(true, Track_Bonus, i, sQuery, sizeof(sQuery)); - gH_SQL.Query(SQL_Recalculate_Callback, sQuery, (i << 8) | 1, DBPrio_High); + if (!Shavit_GetStyleSettingBool(i, "unranked") && Shavit_GetStyleSettingFloat(i, "rankingmultiplier") != 0.0) + { + FormatRecalculate(true, Track_Main, i, sQuery, sizeof(sQuery)); + gH_SQL_b.Query(SQL_Recalculate_Callback, sQuery, (i << 8) | 0, DBPrio_High); + FormatRecalculate(true, Track_Bonus, i, sQuery, sizeof(sQuery)); + gH_SQL.Query(SQL_Recalculate_Callback, sQuery, (i << 8) | 1, DBPrio_High); + } } } @@ -912,6 +930,11 @@ public void Shavit_OnFinish_Post(int client, int style, float time, int jumps, i return; } + if (Shavit_GetStyleSettingBool(style, "unranked") || Shavit_GetStyleSettingFloat(style, "rankingmultiplier") == 0.0) + { + return; + } + #if defined DEBUG PrintToServer("Recalculating points. (%s, %d, %d)", map, track, style); #endif @@ -948,7 +971,7 @@ void UpdateAllPoints(bool recalcall = false) char sQuery[512]; char sLastLogin[256]; - if (recalcall || gCV_LastLoginRecalculate.IntValue == 0) + if (!recalcall && gCV_LastLoginRecalculate.IntValue > 0) { FormatEx(sLastLogin, sizeof(sLastLogin), "lastlogin > %d", (GetTime() - gCV_LastLoginRecalculate.IntValue * 60)); }