From 46f5d83c1adf08000dd7d415ea272ce5833e745a Mon Sep 17 00:00:00 2001 From: shavit Date: Fri, 22 Feb 2019 14:35:32 +0200 Subject: [PATCH 01/27] !replay now moves you to spectator (#739) --- addons/sourcemod/scripting/shavit-replay.sp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/addons/sourcemod/scripting/shavit-replay.sp b/addons/sourcemod/scripting/shavit-replay.sp index e7d6232de..77dfb9982 100644 --- a/addons/sourcemod/scripting/shavit-replay.sp +++ b/addons/sourcemod/scripting/shavit-replay.sp @@ -29,6 +29,7 @@ #undef REQUIRE_EXTENSIONS #include #include +#include #define REPLAY_FORMAT_V2 "{SHAVITREPLAYFORMAT}{V2}" #define REPLAY_FORMAT_FINAL "{SHAVITREPLAYFORMAT}{FINAL}" @@ -2108,7 +2109,22 @@ public Action Command_Replay(int client, int args) return Plugin_Handled; } - if(GetClientTeam(client) != 1 || GetSpectatorTarget(client) != gA_CentralCache.iClient) + if(GetClientTeam(client) > 1) + { + if(gEV_Type == Engine_TF2) + { + TF2_ChangeClientTeam(client, TFTeam_Spectator); + } + + else + { + ChangeClientTeam(client, CS_TEAM_SPECTATOR); + } + + SetEntPropEnt(client, Prop_Send, "m_hObserverTarget", gA_CentralCache.iClient); + } + + else if(GetSpectatorTarget(client) != gA_CentralCache.iClient) { Shavit_PrintToChat(client, "%T", "CentralReplaySpectator", client, gS_ChatStrings.sWarning, gS_ChatStrings.sText, gS_ChatStrings.sVariable, gS_ChatStrings.sText); From 62877282d048918216e18c9cfb68b03a40e7cb71 Mon Sep 17 00:00:00 2001 From: shavit Date: Fri, 22 Feb 2019 15:16:38 +0200 Subject: [PATCH 02/27] HUD PB split (#732) --- addons/sourcemod/scripting/shavit-hud.sp | 35 ++++++++++++++----- .../translations/shavit-hud.phrases.txt | 4 +++ 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/addons/sourcemod/scripting/shavit-hud.sp b/addons/sourcemod/scripting/shavit-hud.sp index b587b834c..3e34d30ae 100644 --- a/addons/sourcemod/scripting/shavit-hud.sp +++ b/addons/sourcemod/scripting/shavit-hud.sp @@ -39,6 +39,7 @@ #define HUD2_STYLE (1 << 5) #define HUD2_RANK (1 << 6) #define HUD2_TRACK (1 << 7) +#define HUD2_SPLITPB (1 << 7) #define HUD_DEFAULT (HUD_MASTER|HUD_CENTER|HUD_ZONEHUD|HUD_OBSERVE|HUD_TOPLEFT|HUD_SYNC|HUD_TIMELEFT|HUD_2DVEL|HUD_SPECTATORS) #define HUD_DEFAULT2 0 @@ -645,6 +646,10 @@ Action ShowHUDMenu(int client, int item) FormatEx(sHudItem, 64, "%T", "HudTrackText", client); menu.AddItem(sInfo, sHudItem); + FormatEx(sInfo, 16, "@%d", HUD2_SPLITPB); + FormatEx(sHudItem, 64, "%T", "HudSplitPbText", client); + menu.AddItem(sInfo, sHudItem); + menu.ExitButton = true; menu.DisplayAt(client, item, 60); @@ -1493,21 +1498,35 @@ void UpdateTopLeftHUD(int client, bool wait) char sWRName[MAX_NAME_LENGTH]; Shavit_GetWRName(style, sWRName, MAX_NAME_LENGTH, track); - float fPBTime = Shavit_GetClientPB(target, style, track); + char sTopLeft[128]; + FormatEx(sTopLeft, 128, "WR: %s (%s)", sWRTime, sWRName); - char sPBTime[16]; - FormatSeconds(fPBTime, sPBTime, MAX_NAME_LENGTH); + float fTargetPB = Shavit_GetClientPB(target, style, track); + char sTargetPB[64]; + FormatSeconds(fTargetPB, sTargetPB, 64); + Format(sTargetPB, 64, "%T: %s", "HudBestText", client, sTargetPB); - char sTopLeft[128]; + float fSelfPB = Shavit_GetClientPB(client, style, track); + char sSelfPB[64]; + FormatSeconds(fSelfPB, sSelfPB, 64); + Format(sSelfPB, 64, "%T: %s", "HudBestText", client, sSelfPB); - if(fPBTime != 0.0) + if((gI_HUD2Settings[client] & HUD2_SPLITPB) == 0 && target != client) { - FormatEx(sTopLeft, 128, "WR: %s (%s)\n%T: %s (#%d)", sWRTime, sWRName, "HudBestText", client, sPBTime, Shavit_GetRankForTime(style, fPBTime, track)); + if(fTargetPB != 0.0) + { + Format(sTopLeft, 128, "%s\n%s (%N)", sTopLeft, sTargetPB, target); + } + + if(fSelfPB != 0.0) + { + Format(sTopLeft, 128, "%s\n%s (%N)", sTopLeft, sSelfPB, client); + } } - else + else if(fSelfPB != 0.0) { - FormatEx(sTopLeft, 128, "WR: %s (%s)", sWRTime, sWRName); + Format(sTopLeft, 128, "%s\n%s (#%d)", sTopLeft, sSelfPB, Shavit_GetRankForTime(style, fSelfPB, track)); } SetHudTextParams(0.01, 0.01, 2.5, 255, 255, 255, 255, 0, 0.0, 0.0, 0.0); diff --git a/addons/sourcemod/translations/shavit-hud.phrases.txt b/addons/sourcemod/translations/shavit-hud.phrases.txt index 6c1cc5d09..a4c21cd2b 100644 --- a/addons/sourcemod/translations/shavit-hud.phrases.txt +++ b/addons/sourcemod/translations/shavit-hud.phrases.txt @@ -131,6 +131,10 @@ { "en" "Timer track" } + "HudSplitPbText" + { + "en" "Split PB" + } // ---------- Record Bots ---------- // "ReplayText" { From 942d6d967511a0220ef9c168b9b374e86349c4b2 Mon Sep 17 00:00:00 2001 From: shavit Date: Fri, 22 Feb 2019 17:11:55 +0200 Subject: [PATCH 03/27] Added Shavit_IsPaused. --- addons/sourcemod/scripting/include/shavit.inc | 11 ++++++++++- addons/sourcemod/scripting/shavit-core.sp | 6 ++++++ addons/sourcemod/scripting/shavit-hud.sp | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/addons/sourcemod/scripting/include/shavit.inc b/addons/sourcemod/scripting/include/shavit.inc index d266ab6fc..a88baa22e 100644 --- a/addons/sourcemod/scripting/include/shavit.inc +++ b/addons/sourcemod/scripting/include/shavit.inc @@ -23,7 +23,7 @@ #endif #define _shavit_included -#define SHAVIT_VERSION "2.4.0" +#define SHAVIT_VERSION "2.4.1" #define STYLE_LIMIT 256 #define MAX_ZONES 64 #define MAX_NAME_LENGTH_SQL 32 @@ -1212,6 +1212,14 @@ native StringMap Shavit_GetMapTiers(); */ native bool Shavit_HasStyleAccess(int client, int style); +/** + * Determines whether a client's timer is paused or not. + * + * @param client Client index. + * @return Boolean value. + */ +native bool Shavit_IsPaused(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. @@ -1315,6 +1323,7 @@ public void __pl_shavit_SetNTVOptional() MarkNativeAsOptional("Shavit_InsideZone"); MarkNativeAsOptional("Shavit_IsClientCreatingZone"); MarkNativeAsOptional("Shavit_IsKZMap"); + MarkNativeAsOptional("Shavit_IsPaused"); MarkNativeAsOptional("Shavit_IsPracticeMode"); MarkNativeAsOptional("Shavit_IsReplayDataLoaded"); MarkNativeAsOptional("Shavit_LoadSnapshot"); diff --git a/addons/sourcemod/scripting/shavit-core.sp b/addons/sourcemod/scripting/shavit-core.sp index bf00d8821..52bb8e51a 100644 --- a/addons/sourcemod/scripting/shavit-core.sp +++ b/addons/sourcemod/scripting/shavit-core.sp @@ -180,6 +180,7 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max CreateNative("Shavit_GetTimerStatus", Native_GetTimerStatus); CreateNative("Shavit_HasStyleAccess", Native_HasStyleAccess); CreateNative("Shavit_IsKZMap", Native_IsKZMap); + CreateNative("Shavit_IsPaused", Native_IsPaused); CreateNative("Shavit_IsPracticeMode", Native_IsPracticeMode); CreateNative("Shavit_LoadSnapshot", Native_LoadSnapshot); CreateNative("Shavit_LogMessage", Native_LogMessage); @@ -1240,6 +1241,11 @@ public int Native_SetPracticeMode(Handle handler, int numParams) gA_Timers[client].bPracticeMode = practice; } +public int Native_IsPaused(Handle handler, int numParams) +{ + return view_as(gA_Timers[GetNativeCell(1)].bPaused); +} + public int Native_IsPracticeMode(Handle handler, int numParams) { return view_as(gA_Timers[GetNativeCell(1)].bPracticeMode); diff --git a/addons/sourcemod/scripting/shavit-hud.sp b/addons/sourcemod/scripting/shavit-hud.sp index 2fbdf8e38..3be2d49a2 100644 --- a/addons/sourcemod/scripting/shavit-hud.sp +++ b/addons/sourcemod/scripting/shavit-hud.sp @@ -1224,7 +1224,7 @@ int AddHUDToBuffer_CSGO(int client, huddata_t data, char[] buffer, int maxlen) StrCat(buffer, maxlen, ""); return iLines; -} +} void UpdateMainHUD(int client) { From 5be987828b3d59281f9409e0626ada2567123518 Mon Sep 17 00:00:00 2001 From: shavit Date: Fri, 22 Feb 2019 17:24:20 +0200 Subject: [PATCH 04/27] Fixed checkpoints exploit and CP menu bug. --- addons/sourcemod/scripting/shavit-misc.sp | 31 ++++++++++++++----- .../translations/shavit-misc.phrases.txt | 5 +++ 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/addons/sourcemod/scripting/shavit-misc.sp b/addons/sourcemod/scripting/shavit-misc.sp index 29f0c7c7e..698d34e99 100644 --- a/addons/sourcemod/scripting/shavit-misc.sp +++ b/addons/sourcemod/scripting/shavit-misc.sp @@ -1454,13 +1454,10 @@ public Action Command_Save(int client, int args) } } - else + else if(SaveCheckpoint(client, index, bOverflow)) { - if(SaveCheckpoint(client, index, bOverflow)) - { - gA_CheckpointsCache[client].iCurrentCheckpoint = (bOverflow)? iMaxCPs:++gA_CheckpointsCache[client].iCheckpoints; - Shavit_PrintToChat(client, "%T", "MiscCheckpointsSaved", client, gA_CheckpointsCache[client].iCurrentCheckpoint, gS_ChatStrings.sVariable, gS_ChatStrings.sText); - } + gA_CheckpointsCache[client].iCurrentCheckpoint = (bOverflow)? iMaxCPs:++gA_CheckpointsCache[client].iCheckpoints; + Shavit_PrintToChat(client, "%T", "MiscCheckpointsSaved", client, gA_CheckpointsCache[client].iCurrentCheckpoint, gS_ChatStrings.sVariable, gS_ChatStrings.sText); } return Plugin_Handled; @@ -1591,8 +1588,10 @@ public int MenuHandler_Checkpoints(Menu menu, MenuAction action, int param1, int return 0; } - SaveCheckpoint(param1, ++gA_CheckpointsCache[param1].iCheckpoints); - gA_CheckpointsCache[param1].iCurrentCheckpoint = gA_CheckpointsCache[param1].iCheckpoints; + if(SaveCheckpoint(param1, gA_CheckpointsCache[param1].iCheckpoints + 1)) + { + gA_CheckpointsCache[param1].iCurrentCheckpoint = ++gA_CheckpointsCache[param1].iCheckpoints; + } } else @@ -1692,6 +1691,13 @@ bool SaveCheckpoint(int client, int index, bool overflow = false) return false; } + else if(Shavit_IsPaused(client) || Shavit_IsPaused(target)) + { + Shavit_PrintToChat(client, "%T", "CommandNoPause", client, gS_ChatStrings.sVariable, gS_ChatStrings.sText); + + return false; + } + char sKey[32]; int iSerial = GetClientSerial(client); FormatEx(sKey, 32, "%d_%d", iSerial, index); @@ -1893,6 +1899,13 @@ void TeleportToCheckpoint(int client, int index, bool suppressMessage) return; } + else if(Shavit_IsPaused(client)) + { + Shavit_PrintToChat(client, "%T", "CommandNoPause", client, gS_ChatStrings.sVariable, gS_ChatStrings.sText); + + return; + } + float pos[3]; CopyArray(cpcache.fPosition, pos, 3); @@ -1916,6 +1929,7 @@ void TeleportToCheckpoint(int client, int index, bool suppressMessage) timer_snapshot_t snapshot; CopyArray(cpcache.aSnapshot, snapshot, sizeof(timer_snapshot_t)); Shavit_LoadSnapshot(client, snapshot); + Shavit_ResumeTimer(client); float ang[3]; CopyArray(cpcache.fAngles, ang, 3); @@ -2703,6 +2717,7 @@ void LoadState(int client) Shavit_LoadSnapshot(client, gA_SaveStates[client]); Shavit_SetPracticeMode(client, gB_SaveStatesSegmented[client], false); + Shavit_ResumeTimer(client); if(gB_Replay && gA_SaveFrames[client] != null) { diff --git a/addons/sourcemod/translations/shavit-misc.phrases.txt b/addons/sourcemod/translations/shavit-misc.phrases.txt index dc4a070d3..8920cf7cc 100644 --- a/addons/sourcemod/translations/shavit-misc.phrases.txt +++ b/addons/sourcemod/translations/shavit-misc.phrases.txt @@ -11,6 +11,11 @@ "#format" "{1:s},{2:s},{3:s},{4:s}" "en" "You have to be {1}alive{2} or {3}spectate a player{4} to use this command." } + "CommandNoPause" + { + "#format" "{1:s},{2:s}" + "en" "Your timer has to be {1}resumed{2} to use this command." + } "CommandDisabled" { "#format" "{1:s},{2:s}" From 0bad2d64579714457277d14979d930f9d630faeb Mon Sep 17 00:00:00 2001 From: shavit Date: Fri, 22 Feb 2019 17:48:10 +0200 Subject: [PATCH 05/27] oops --- addons/sourcemod/scripting/shavit-hud.sp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/sourcemod/scripting/shavit-hud.sp b/addons/sourcemod/scripting/shavit-hud.sp index 3be2d49a2..eebebd24d 100644 --- a/addons/sourcemod/scripting/shavit-hud.sp +++ b/addons/sourcemod/scripting/shavit-hud.sp @@ -39,7 +39,7 @@ #define HUD2_STYLE (1 << 5) #define HUD2_RANK (1 << 6) #define HUD2_TRACK (1 << 7) -#define HUD2_SPLITPB (1 << 7) +#define HUD2_SPLITPB (1 << 8) #define HUD_DEFAULT (HUD_MASTER|HUD_CENTER|HUD_ZONEHUD|HUD_OBSERVE|HUD_TOPLEFT|HUD_SYNC|HUD_TIMELEFT|HUD_2DVEL|HUD_SPECTATORS) #define HUD_DEFAULT2 0 From a784b717ff74493a99d6fe89044e720c50fbea5b Mon Sep 17 00:00:00 2001 From: shavit Date: Fri, 22 Feb 2019 17:48:43 +0200 Subject: [PATCH 06/27] Added tier to zone HUD (#675). --- addons/sourcemod/scripting/shavit-hud.sp | 61 ++++++++++++++++++- .../translations/shavit-hud.phrases.txt | 9 +++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/addons/sourcemod/scripting/shavit-hud.sp b/addons/sourcemod/scripting/shavit-hud.sp index eebebd24d..38d9a21e7 100644 --- a/addons/sourcemod/scripting/shavit-hud.sp +++ b/addons/sourcemod/scripting/shavit-hud.sp @@ -40,6 +40,7 @@ #define HUD2_RANK (1 << 6) #define HUD2_TRACK (1 << 7) #define HUD2_SPLITPB (1 << 8) +#define HUD2_MAPTIER (1 << 9) #define HUD_DEFAULT (HUD_MASTER|HUD_CENTER|HUD_ZONEHUD|HUD_OBSERVE|HUD_TOPLEFT|HUD_SYNC|HUD_TIMELEFT|HUD_2DVEL|HUD_SPECTATORS) #define HUD_DEFAULT2 0 @@ -84,6 +85,7 @@ EngineVersion gEV_Type = Engine_Unknown; bool gB_Replay = false; bool gB_Zones = false; bool gB_Sounds = false; +bool gB_Rankings = false; bool gB_BhopStats = false; // cache @@ -91,6 +93,7 @@ int gI_Cycle = 0; color_t gI_Gradient; int gI_GradientDirection = -1; int gI_Styles = 0; +char gS_Map[160]; Handle gH_HUDCookie = null; Handle gH_HUDCookieMain = null; @@ -172,6 +175,7 @@ public void OnPluginStart() gB_Replay = LibraryExists("shavit-replay"); gB_Zones = LibraryExists("shavit-zones"); gB_Sounds = LibraryExists("shavit-sounds"); + gB_Rankings = LibraryExists("shavit-rankings"); gB_BhopStats = LibraryExists("bhopstats"); // HUD handle @@ -232,6 +236,9 @@ public void OnPluginStart() public void OnMapStart() { + GetCurrentMap(gS_Map, 160); + GetMapDisplayName(gS_Map, gS_Map, 160); + if(gB_Late) { Shavit_OnStyleConfigLoaded(-1); @@ -256,6 +263,11 @@ public void OnLibraryAdded(const char[] name) gB_Sounds = true; } + else if(StrEqual(name, "shavit-rankings")) + { + gB_Rankings = true; + } + else if(StrEqual(name, "bhopstats")) { gB_BhopStats = true; @@ -279,6 +291,11 @@ public void OnLibraryRemoved(const char[] name) gB_Sounds = false; } + else if(StrEqual(name, "shavit-rankings")) + { + gB_Rankings = false; + } + else if(StrEqual(name, "bhopstats")) { gB_BhopStats = false; @@ -650,6 +667,13 @@ Action ShowHUDMenu(int client, int item) FormatEx(sHudItem, 64, "%T", "HudSplitPbText", client); menu.AddItem(sInfo, sHudItem); + if(gB_Rankings) + { + FormatEx(sInfo, 16, "@%d", HUD2_MAPTIER); + FormatEx(sHudItem, 64, "%T", "HudMapTierText", client); + menu.AddItem(sInfo, sHudItem); + } + menu.ExitButton = true; menu.DisplayAt(client, item, 60); @@ -971,7 +995,23 @@ int AddHUDToBuffer_Source2013(int client, huddata_t data, char[] buffer, int max if((gI_HUDSettings[client] & HUD_ZONEHUD) > 0 && data.iZoneHUD != ZoneHUD_None) { - FormatEx(sLine, 128, "%T ", (data.iZoneHUD == ZoneHUD_Start)? "HudInStartZone":"HudInEndZone", client, data.iSpeed); + if(gB_Rankings && (gI_HUD2Settings[client] & HUD2_MAPTIER) == 0) + { + FormatEx(sLine, 128, "%T", "HudZoneTier", client, Shavit_GetMapTier(gS_Map)); + AddHUDLine(buffer, maxlen, sLine, iLines); + iLines++; + } + + if(data.iZoneHUD == ZoneHUD_Start) + { + FormatEx(sLine, 128, "%T ", "HudInStartZone", client, data.iSpeed); + } + + else + { + FormatEx(sLine, 128, "%T ", "HudInEndZone", client, data.iSpeed); + } + AddHUDLine(buffer, maxlen, sLine, iLines); return ++iLines; @@ -1100,6 +1140,7 @@ int AddHUDToBuffer_CSGO(int client, huddata_t data, char[] buffer, int maxlen) { FormatEx(sLine, 128, "%d u/s", data.iSpeed); AddHUDLine(buffer, maxlen, sLine, iLines); + iLines++; } } @@ -1120,8 +1161,24 @@ int AddHUDToBuffer_CSGO(int client, huddata_t data, char[] buffer, int maxlen) char sZoneHUD[64]; FormatEx(sZoneHUD, 64, "", ((gI_Gradient.r << 16) + (gI_Gradient.g << 8) + (gI_Gradient.b))); StrCat(buffer, maxlen, sZoneHUD); + + if(data.iZoneHUD == ZoneHUD_Start) + { + if(gB_Rankings && (gI_HUD2Settings[client] & HUD2_MAPTIER) == 0) + { + FormatEx(sZoneHUD, 32, "%T", "HudZoneTier", client, Shavit_GetMapTier(gS_Map)); + AddHUDLine(buffer, maxlen, sZoneHUD, iLines); + iLines++; + } + + FormatEx(sZoneHUD, 64, "%T", "HudInStartZoneCSGO", client, data.iSpeed); + } + + else + { + FormatEx(sZoneHUD, 64, "%T", "HudInEndZoneCSGO", client, data.iSpeed); + } - FormatEx(sZoneHUD, 64, "%T", (data.iZoneHUD == ZoneHUD_Start)? "HudInStartZoneCSGO":"HudInEndZoneCSGO", client, data.iSpeed); StrCat(buffer, maxlen, sZoneHUD); return ++iLines; diff --git a/addons/sourcemod/translations/shavit-hud.phrases.txt b/addons/sourcemod/translations/shavit-hud.phrases.txt index a4c21cd2b..b266d17a2 100644 --- a/addons/sourcemod/translations/shavit-hud.phrases.txt +++ b/addons/sourcemod/translations/shavit-hud.phrases.txt @@ -6,6 +6,11 @@ { "en" "Start Zone" } + "HudZoneTier" + { + "#format" "{1:d}" + "en" "Tier {1}" + } "HudInStartZone" { "#format" "{1:d}" @@ -135,6 +140,10 @@ { "en" "Split PB" } + "HudMapTierText" + { + "en" "Map tier" + } // ---------- Record Bots ---------- // "ReplayText" { From 875d71be3e192756bb2c20686ccd76387b70d991 Mon Sep 17 00:00:00 2001 From: shavit Date: Fri, 22 Feb 2019 17:51:59 +0200 Subject: [PATCH 07/27] Added {rank} to scoreboard clan tag (#702). --- addons/sourcemod/scripting/shavit-misc.sp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/addons/sourcemod/scripting/shavit-misc.sp b/addons/sourcemod/scripting/shavit-misc.sp index 698d34e99..d7bd2e75f 100644 --- a/addons/sourcemod/scripting/shavit-misc.sp +++ b/addons/sourcemod/scripting/shavit-misc.sp @@ -286,7 +286,7 @@ public void OnPluginStart() gCV_AdvertisementInterval = CreateConVar("shavit_misc_advertisementinterval", "600.0", "Interval between each chat advertisement.\nConfiguration file for those is configs/shavit-advertisements.cfg.\nSet to 0.0 to disable.\nRequires server restart for changes to take effect.", 0, true, 0.0); gCV_Checkpoints = CreateConVar("shavit_misc_checkpoints", "1", "Allow players to save and teleport to checkpoints.", 0, true, 0.0, true, 1.0); gCV_RemoveRagdolls = CreateConVar("shavit_misc_removeragdolls", "1", "Remove ragdolls after death?\n0 - Disabled\n1 - Only remove replay bot ragdolls.\n2 - Remove all ragdolls.", 0, true, 0.0, true, 2.0); - gCV_ClanTag = CreateConVar("shavit_misc_clantag", "{tr}{styletag} :: {time}", "Custom clantag for players.\n0 - Disabled\n{styletag} - style settings from shavit-styles.cfg.\n{style} - style name.\n{time} - formatted time.\n{tr} - first letter of track, if not default.", 0); + gCV_ClanTag = CreateConVar("shavit_misc_clantag", "{tr}{styletag} :: {time}", "Custom clantag for players.\n0 - Disabled\n{styletag} - style tag.\n{style} - style name.\n{time} - formatted time.\n{tr} - first letter of track.\n{rank} - player rank.", 0); gCV_DropAll = CreateConVar("shavit_misc_dropall", "1", "Allow all weapons to be dropped?\n0 - Disabled\n1 - Enabled", 0, true, 0.0, true, 1.0); gCV_ResetTargetname = CreateConVar("shavit_misc_resettargetname", "0", "Reset the player's targetname upon timer start?\nRecommended to leave disabled. Enable via per-map configs when necessary.\n0 - Disabled\n1 - Enabled", 0, true, 0.0, true, 1.0); gCV_RestoreStates = CreateConVar("shavit_misc_restorestates", "0", "Save the players' timer/position etc.. when they die/change teams,\nand load the data when they spawn?\n0 - Disabled\n1 - Enabled", 0, true, 0.0, true, 1.0); @@ -873,12 +873,20 @@ void UpdateClanTag(int client) GetTrackName(client, track, sTrack, 3); } + char sRank[8]; + + if(gB_Rankings) + { + IntToString(Shavit_GetRank(client), sRank, 8); + } + char sCustomTag[32]; strcopy(sCustomTag, 32, sTag); ReplaceString(sCustomTag, 32, "{style}", gS_StyleStrings[gI_Style[client]].sStyleName); ReplaceString(sCustomTag, 32, "{styletag}", gS_StyleStrings[gI_Style[client]].sClanTag); ReplaceString(sCustomTag, 32, "{time}", sTime); ReplaceString(sCustomTag, 32, "{tr}", sTrack); + ReplaceString(sCustomTag, 32, "{rank}", sRank); CS_SetClientClanTag(client, sCustomTag); } From 5468a942435cb303f30324c302d47c655d98f55b Mon Sep 17 00:00:00 2001 From: shavit Date: Fri, 22 Feb 2019 19:36:48 +0200 Subject: [PATCH 08/27] Separated unset start zone message per track (#735). --- addons/sourcemod/scripting/shavit-core.sp | 20 ++++++++++++++++++- .../translations/shavit-core.phrases.txt | 4 ++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/addons/sourcemod/scripting/shavit-core.sp b/addons/sourcemod/scripting/shavit-core.sp index 52bb8e51a..81788b18d 100644 --- a/addons/sourcemod/scripting/shavit-core.sp +++ b/addons/sourcemod/scripting/shavit-core.sp @@ -223,6 +223,7 @@ public void OnPluginStart() gH_Forwards_OnTimerIncrementPost = CreateGlobalForward("Shavit_OnTimeIncrementPost", ET_Event, Param_Cell, Param_Cell, Param_Array); LoadTranslations("shavit-core.phrases"); + LoadTranslations("shavit-common.phrases"); // game types gEV_Type = GetEngineVersion(); @@ -471,7 +472,10 @@ public Action Command_StartTimer(int client, int args) else { - Shavit_PrintToChat(client, "%T", "StartZoneUndefined", client, gS_ChatStrings.sWarning, gS_ChatStrings.sText); + char sTrack[32]; + GetTrackName(client, track, sTrack, 32); + + Shavit_PrintToChat(client, "%T", "StartZoneUndefined", client, gS_ChatStrings.sWarning, gS_ChatStrings.sText, gS_ChatStrings.sVariable2, sTrack, gS_ChatStrings.sText); } return Plugin_Handled; @@ -2403,3 +2407,17 @@ void UpdateStyleSettings(int client) SetEntityGravity(client, view_as(gA_StyleSettings[gA_Timers[client].iStyle].fGravityMultiplier)); } + +void GetTrackName(int client, int track, char[] output, int size) +{ + if(track < 0 || track >= TRACKS_SIZE) + { + FormatEx(output, size, "%T", "Track_Unknown", client); + + return; + } + + static char sTrack[16]; + FormatEx(sTrack, 16, "Track_%d", track); + FormatEx(output, size, "%T", sTrack, client); +} diff --git a/addons/sourcemod/translations/shavit-core.phrases.txt b/addons/sourcemod/translations/shavit-core.phrases.txt index d5ada2b12..0fe6afda8 100644 --- a/addons/sourcemod/translations/shavit-core.phrases.txt +++ b/addons/sourcemod/translations/shavit-core.phrases.txt @@ -113,8 +113,8 @@ // ---------- Zones ---------- // "StartZoneUndefined" { - "#format" "{1:s},{2:s}" - "en" "Your timer {1}will not{2} start as a start zone for the map is not defined." + "#format" "{1:s},{2:s},{3:s},{4:s},{5:s}" + "en" "Your timer {1}will not{2} start because the {3}{4}{5} start zone is not set." } "EndZoneUndefined" { From a712c1daeb35499a79fbccf420e166ed01b28e2a Mon Sep 17 00:00:00 2001 From: shavit Date: Fri, 22 Feb 2019 21:21:59 +0200 Subject: [PATCH 09/27] Fixed replay HUD time display issues for timescale styles (#689). --- addons/sourcemod/scripting/shavit-hud.sp | 2 +- addons/sourcemod/scripting/shavit-replay.sp | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/addons/sourcemod/scripting/shavit-hud.sp b/addons/sourcemod/scripting/shavit-hud.sp index 38d9a21e7..0dff987bf 100644 --- a/addons/sourcemod/scripting/shavit-hud.sp +++ b/addons/sourcemod/scripting/shavit-hud.sp @@ -1324,7 +1324,7 @@ void UpdateMainHUD(int client) if(iReplayStyle != -1) { - fReplayTime = (Shavit_GetReplayTime(iReplayStyle, iReplayTrack) * gA_StyleSettings[iReplayStyle].fTimescale); + fReplayTime = Shavit_GetReplayTime(iReplayStyle, iReplayTrack); fReplayLength = Shavit_GetReplayLength(iReplayStyle, iReplayTrack); } } diff --git a/addons/sourcemod/scripting/shavit-replay.sp b/addons/sourcemod/scripting/shavit-replay.sp index 77dfb9982..8e2cb7c1c 100644 --- a/addons/sourcemod/scripting/shavit-replay.sp +++ b/addons/sourcemod/scripting/shavit-replay.sp @@ -495,7 +495,7 @@ public int Native_GetReplayTime(Handle handler, int numParams) return view_as(GetReplayLength(Track_Main, track)); } - return view_as(float(gI_ReplayTick[style]) / gF_Tickrate); + return view_as(float(gI_ReplayTick[style]) / gF_Tickrate * gA_StyleSettings[style].fTimescale); } public int Native_HijackAngles(Handle handler, int numParams) @@ -2446,9 +2446,7 @@ float GetReplayLength(int style, int track) return gA_FrameCache[style][track].fTime; } - float fWRTime = Shavit_GetWorldRecord(style, track); - - return fWRTime; + return Shavit_GetWorldRecord(style, track) * gA_StyleSettings[style].fTimescale; } void GetReplayName(int style, int track, char[] buffer, int length) From dd8e5a76dd981f6e9899d7946eeb7516c6b3bc01 Mon Sep 17 00:00:00 2001 From: shavit Date: Fri, 22 Feb 2019 21:42:18 +0200 Subject: [PATCH 10/27] Fixed improper targetname/classname set for CP (#700). --- addons/sourcemod/scripting/shavit-misc.sp | 37 +++++++++++------------ 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/addons/sourcemod/scripting/shavit-misc.sp b/addons/sourcemod/scripting/shavit-misc.sp index d7bd2e75f..7585f6ea5 100644 --- a/addons/sourcemod/scripting/shavit-misc.sp +++ b/addons/sourcemod/scripting/shavit-misc.sp @@ -1958,6 +1958,23 @@ void TeleportToCheckpoint(int client, int index, bool suppressMessage) vel = NULL_VECTOR; } + if(cpcache.iTargetname != -1) + { + char sTargetname[64]; + gA_Targetnames.GetString(cpcache.iTargetname, sTargetname, 64); + + SetEntPropString(client, Prop_Data, "m_iName", sTargetname); + Shavit_PrintToChat(client, "set name %s", sTargetname); + } + + if(cpcache.iClassname != -1) + { + char sClassname[64]; + gA_Classnames.GetString(cpcache.iClassname, sClassname, 64); + + SetEntPropString(client, Prop_Data, "m_iClassname", sClassname); + } + TeleportEntity(client, pos, ((gI_CheckpointsSettings[client] & CP_ANGLES) > 0 || cpcache.bSegmented)? ang:NULL_VECTOR, vel); @@ -1980,26 +1997,6 @@ void TeleportToCheckpoint(int client, int index, bool suppressMessage) SetEntPropFloat(client, Prop_Send, "m_flLaggedMovementValue", cpcache.fSpeed); SetEntPropEnt(client, Prop_Data, "m_hGroundEntity", cpcache.iGroundEntity); - int iTargetname = gA_Targetnames.FindValue(cpcache.iTargetname); - - if(iTargetname != -1) - { - char sTargetname[64]; - gA_Targetnames.GetString(iTargetname, sTargetname, 64); - - SetEntPropString(client, Prop_Data, "m_iName", sTargetname); - } - - int iClassname = gA_Classnames.FindValue(cpcache.iClassname); - - if(iClassname != -1) - { - char sClassname[64]; - gA_Classnames.GetString(iClassname, sClassname, 64); - - SetEntPropString(client, Prop_Data, "m_iClassname", sClassname); - } - if(gEV_Type != Engine_TF2) { SetEntPropFloat(client, Prop_Send, "m_flStamina", cpcache.fStamina); From b264f5070564e276a2208e218941de40120eb25b Mon Sep 17 00:00:00 2001 From: shavit Date: Sun, 24 Feb 2019 14:07:21 +0200 Subject: [PATCH 11/27] Fixed commands erroring at IsClientInGame when ran from console/rcon. --- addons/sourcemod/scripting/shavit-core.sp | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/addons/sourcemod/scripting/shavit-core.sp b/addons/sourcemod/scripting/shavit-core.sp index 81788b18d..351a5119b 100644 --- a/addons/sourcemod/scripting/shavit-core.sp +++ b/addons/sourcemod/scripting/shavit-core.sp @@ -1106,19 +1106,26 @@ public int Native_PrintToChat(Handle handler, int numParams) { int client = GetNativeCell(1); - if(!IsClientInGame(client)) - { - gB_StopChatSound = false; - - return; - } - static int iWritten = 0; // useless? char sBuffer[300]; FormatNativeString(0, 2, 3, 300, iWritten, sBuffer); Format(sBuffer, 300, "%s %s%s", gS_ChatStrings.sPrefix, gS_ChatStrings.sText, sBuffer); + if(client == 0) + { + PrintToServer("%s", sBuffer); + + return 0; + } + + if(!IsClientInGame(client)) + { + gB_StopChatSound = false; + + return 0; + } + Handle hSayText2 = StartMessageOne("SayText2", client, USERMSG_RELIABLE|USERMSG_BLOCKHOOKS); if(gB_Protobuf) From 6fba2bca9c108b7abd53fa79c7f74f02f07db134 Mon Sep 17 00:00:00 2001 From: shavit Date: Sun, 24 Feb 2019 15:10:08 +0200 Subject: [PATCH 12/27] Added Shavit_DeleteReplay native. --- addons/sourcemod/scripting/include/shavit.inc | 12 ++++ addons/sourcemod/scripting/shavit-replay.sp | 65 ++++++++++++++----- 2 files changed, 61 insertions(+), 16 deletions(-) diff --git a/addons/sourcemod/scripting/include/shavit.inc b/addons/sourcemod/scripting/include/shavit.inc index a88baa22e..bb8ed1744 100644 --- a/addons/sourcemod/scripting/include/shavit.inc +++ b/addons/sourcemod/scripting/include/shavit.inc @@ -878,6 +878,17 @@ native void Shavit_PauseTimer(int client); */ native void Shavit_ResumeTimer(int client); +/** + * Deletes the specified replay file. + * Replay data will be unloaded if necessary. + * + * @param map Map display name. + * @param style Bhop style. + * @param track Timer track. + * @return true if replay existed, false otherwise. + */ +native bool Shavit_DeleteReplay(const char[] map, int style, int track); + /** * Retrieves the engine time of the replay bot's first frame. * @@ -1273,6 +1284,7 @@ public SharedPlugin __pl_shavit = #if !defined REQUIRE_PLUGIN public void __pl_shavit_SetNTVOptional() { + MarkNativeAsOptional("Shavit_DeleteReplay"); MarkNativeAsOptional("Shavit_FinishMap"); MarkNativeAsOptional("Shavit_ForceHUDUpdate"); MarkNativeAsOptional("Shavit_FormatChat"); diff --git a/addons/sourcemod/scripting/shavit-replay.sp b/addons/sourcemod/scripting/shavit-replay.sp index 8e2cb7c1c..525a26f11 100644 --- a/addons/sourcemod/scripting/shavit-replay.sp +++ b/addons/sourcemod/scripting/shavit-replay.sp @@ -154,6 +154,7 @@ public Plugin myinfo = public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) { + CreateNative("Shavit_DeleteReplay", Native_DeleteReplay); CreateNative("Shavit_GetReplayBotCurrentFrame", Native_GetReplayBotIndex); CreateNative("Shavit_GetReplayBotFirstFrame", Native_GetReplayBotFirstFrame); CreateNative("Shavit_GetReplayBotIndex", Native_GetReplayBotIndex); @@ -312,6 +313,53 @@ public void AdminMenu_DeleteReplay(Handle topmenu, TopMenuAction action, TopMenu } } +void UnloadReplay(int style, int track) +{ + if(gCV_CentralBot.BoolValue && gA_CentralCache.iStyle == style && gA_CentralCache.iTrack == track) + { + StopCentralReplay(0); + } + + gA_Frames[style][track].Clear(); + gA_FrameCache[style][track].iFrameCount = 0; + gA_FrameCache[style][track].fTime = 0.0; + gA_FrameCache[style][track].bNewFormat = false; + strcopy(gA_FrameCache[style][track].sReplayName, MAX_NAME_LENGTH, "invalid"); + gI_ReplayTick[style] = -1; + + if(gI_ReplayBotClient[style] != 0) + { + UpdateReplayInfo(gI_ReplayBotClient[style], style, 0.0, track); + } +} + +public int Native_DeleteReplay(Handle handler, int numParams) +{ + char sMap[160]; + GetNativeString(1, sMap, 160); + + int iStyle = GetNativeCell(2); + int iTrack = GetNativeCell(3); + + char sTrack[4]; + FormatEx(sTrack, 4, "_%d", iTrack); + + char sPath[PLATFORM_MAX_PATH]; + FormatEx(sPath, PLATFORM_MAX_PATH, "%s/%d/%s%s.replay", gS_ReplayFolder, iStyle, gS_Map, (iTrack > 0)? sTrack:""); + + if(!FileExists(sPath) || !DeleteFile(sPath)) + { + return false; + } + + if(StrEqual(sMap, gS_Map)) + { + UnloadReplay(iStyle, iTrack); + } + + return true; +} + public int Native_GetReplayBotFirstFrame(Handle handler, int numParams) { SetNativeCellRef(2, gF_StartTick[GetNativeCell(1)]); @@ -1112,22 +1160,7 @@ bool DeleteReplay(int style, int track) return false; } - if(gCV_CentralBot.BoolValue && gA_CentralCache.iStyle == style && gA_CentralCache.iTrack == track) - { - StopCentralReplay(0); - } - - gA_Frames[style][track].Clear(); - gA_FrameCache[style][track].iFrameCount = 0; - gA_FrameCache[style][track].fTime = 0.0; - gA_FrameCache[style][track].bNewFormat = false; - strcopy(gA_FrameCache[style][track].sReplayName, MAX_NAME_LENGTH, "invalid"); - gI_ReplayTick[style] = -1; - - if(gI_ReplayBotClient[style] != 0) - { - UpdateReplayInfo(gI_ReplayBotClient[style], style, 0.0, track); - } + UnloadReplay(style, track); return true; } From 78bba83fd0641016edddfbd9df5c64530de85380 Mon Sep 17 00:00:00 2001 From: shavit Date: Sun, 24 Feb 2019 15:53:51 +0200 Subject: [PATCH 13/27] Added Shavit_ReloadLeaderboards. --- addons/sourcemod/scripting/include/shavit.inc | 8 ++++++++ addons/sourcemod/scripting/shavit-wr.sp | 9 ++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/addons/sourcemod/scripting/include/shavit.inc b/addons/sourcemod/scripting/include/shavit.inc index bb8ed1744..44f62e725 100644 --- a/addons/sourcemod/scripting/include/shavit.inc +++ b/addons/sourcemod/scripting/include/shavit.inc @@ -762,6 +762,13 @@ native void Shavit_GetWRTime(int style, float &time, int track); */ native float Shavit_GetWorldRecord(int style, int track); +/** + * Reloads WR leaderboards cache for the current map. + * + * @noreturn + */ +native void Shavit_ReloadLeaderboards(); + /** * Saves the WR's record ID for the current map on a variable. * Unused in base plugins, as of pre-1.4b. @@ -1330,6 +1337,7 @@ public void __pl_shavit_SetNTVOptional() MarkNativeAsOptional("Shavit_GetWRName"); MarkNativeAsOptional("Shavit_GetWRRecordID"); MarkNativeAsOptional("Shavit_GetWRTime"); + MarkNativeAsOptional("Shavit_ReloadLeaderboards"); MarkNativeAsOptional("Shavit_HasStyleAccess"); MarkNativeAsOptional("Shavit_HijackAngles"); MarkNativeAsOptional("Shavit_InsideZone"); diff --git a/addons/sourcemod/scripting/shavit-wr.sp b/addons/sourcemod/scripting/shavit-wr.sp index fa55f129f..5a6fef126 100644 --- a/addons/sourcemod/scripting/shavit-wr.sp +++ b/addons/sourcemod/scripting/shavit-wr.sp @@ -107,6 +107,7 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max CreateNative("Shavit_GetWRName", Native_GetWRName); CreateNative("Shavit_GetWRRecordID", Native_GetWRRecordID); CreateNative("Shavit_GetWRTime", Native_GetWRTime); + CreateNative("Shavit_ReloadLeaderboards", Native_ReloadLeaderboards); CreateNative("Shavit_WR_DeleteMap", Native_WR_DeleteMap); // registers library, check "bool LibraryExists(const char[] name)" in order to use with other plugins @@ -556,6 +557,12 @@ public int Native_GetWRTime(Handle handler, int numParams) SetNativeCellRef(2, gF_WRTime[GetNativeCell(1)][GetNativeCell(3)]); } +public int Native_ReloadLeaderboards(Handle handler, int numParams) +{ + UpdateLeaderboards(); + UpdateWRCache(); +} + public int Native_GetWRRecordID(Handle handler, int numParams) { SetNativeCellRef(2, gI_WRRecordID[GetNativeCell(1)][GetNativeCell(3)]); @@ -2309,7 +2316,7 @@ public void SQL_OnFinish_Callback(Database db, DBResultSet results, const char[] void UpdateLeaderboards() { char sQuery[192]; - FormatEx(sQuery, 192, "SELECT style, time, track FROM %splayertimes WHERE map = '%s' ORDER BY time ASC, date ASC;", gS_MySQLPrefix, gS_Map); + FormatEx(sQuery, 192, "SELECT style, time, track FROM %splayertimes WHERE map = '%s' ORDER BY time ASC, date ASC LIMIT 1000;", gS_MySQLPrefix, gS_Map); gH_SQL.Query(SQL_UpdateLeaderboards_Callback, sQuery, 0); } From c767a375b3210f561ab16a06c0c87b347b535b0c Mon Sep 17 00:00:00 2001 From: shavit Date: Sun, 24 Feb 2019 15:54:52 +0200 Subject: [PATCH 14/27] Added sm_wipeplayer. (#568) --- addons/sourcemod/scripting/shavit-core.sp | 217 +++++++++++++++++++- addons/sourcemod/scripting/shavit-replay.sp | 5 + 2 files changed, 220 insertions(+), 2 deletions(-) diff --git a/addons/sourcemod/scripting/shavit-core.sp b/addons/sourcemod/scripting/shavit-core.sp index 351a5119b..49cab303f 100644 --- a/addons/sourcemod/scripting/shavit-core.sp +++ b/addons/sourcemod/scripting/shavit-core.sp @@ -142,6 +142,8 @@ bool gB_StopChatSound = false; bool gB_HookedJump = false; char gS_LogPath[PLATFORM_MAX_PATH]; char gS_DeleteMap[MAXPLAYERS+1][160]; +char gS_WipePlayerID[MAXPLAYERS+1][32]; +char gS_Verification[MAXPLAYERS+1][16]; // flags int gI_StyleFlag[STYLE_LIMIT]; @@ -299,6 +301,7 @@ public void OnPluginStart() // admin RegAdminCmd("sm_deletemap", Command_DeleteMap, ADMFLAG_ROOT, "Deletes all map data. Usage: sm_deletemap "); + RegAdminCmd("sm_wipeplayer", Command_WipePlayer, ADMFLAG_BAN, "Wipes all bhoptimer data for specified player. Usage: sm_wipeplayer "); // commands END // logs @@ -641,6 +644,214 @@ public Action Command_DeleteMap(int client, int args) return Plugin_Handled; } +public Action Command_WipePlayer(int client, int args) +{ + if(args == 0) + { + ReplyToCommand(client, "Usage: sm_wipeplayer \nAfter entering a SteamID, you will be prompted with a verification captcha."); + + return Plugin_Handled; + } + + char sArgString[32]; + GetCmdArgString(sArgString, 32); + + if(strlen(gS_Verification[client]) == 0 || !StrEqual(sArgString, gS_Verification[client])) + { + char sAlphabet[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#"; + + for(int i = 0; i < GetRandomInt(5, 7); i++) + { + gS_Verification[client][i] = sAlphabet[GetRandomInt(0, sizeof(sAlphabet))]; + } + + strcopy(gS_WipePlayerID[client], 32, sArgString); + + Shavit_PrintToChat(client, "Preparing to delete all user data for SteamID %s%s%s. To confirm, enter %s!wipeplayer %s", + gS_ChatStrings.sVariable, sArgString, gS_ChatStrings.sText, gS_ChatStrings.sVariable2, gS_Verification[client]); + } + + else + { + int iLength = ((strlen(gS_WipePlayerID[client]) * 2) + 1); + char[] sEscapedAuthID = new char[iLength]; + gH_SQL.Escape(gS_WipePlayerID[client], sEscapedAuthID, iLength); + + Shavit_PrintToChat(client, "Deleting data for SteamID %s%s%s...", + gS_ChatStrings.sVariable, sEscapedAuthID, gS_ChatStrings.sText); + + DeleteUserData(client, sEscapedAuthID); + + strcopy(gS_Verification[client], 32, ""); + strcopy(gS_WipePlayerID[client], 32, ""); + } + + return Plugin_Handled; +} + +void DeleteUserData(int client, const char[] sAuthID3) +{ + if(gB_Replay) + { + char sQueryGetWorldRecords[256]; + FormatEx(sQueryGetWorldRecords, 256, + "SELECT map, id, style, track FROM %splayertimes WHERE auth = '%s' GROUP BY map, style, track;", + gS_MySQLPrefix, sAuthID3); + + DataPack pack = new DataPack(); + pack.WriteCell(client); + pack.WriteString(sAuthID3); + + gH_SQL.Query(SQL_DeleteUserData_GetRecords_Callback, sQueryGetWorldRecords, pack, DBPrio_High); + } + + else + { + char sQueryDeleteUserTimes[256]; + FormatEx(sQueryDeleteUserTimes, 256, + "DELETE FROM %splayertimes WHERE auth = '%s';", + gS_MySQLPrefix, sAuthID3); + + DataPack steamPack = new DataPack(); + steamPack.WriteString(sAuthID3); + steamPack.WriteCell(client); + + gH_SQL.Query(SQL_DeleteUserTimes_Callback, sQueryDeleteUserTimes, steamPack, DBPrio_High); + } +} + +public void SQL_DeleteUserData_GetRecords_Callback(Database db, DBResultSet results, const char[] error, any data) +{ + DataPack pack = view_as(data); + pack.Reset(); + int client = pack.ReadCell(); + + char sAuthID3[32]; + pack.ReadString(sAuthID3, 32); + delete pack; + + if(results == null) + { + LogError("Timer error! Failed to wipe user data (wipe | get player records). Reason: %s", error); + + return; + } + + Transaction trans = new Transaction(); + + while(results.FetchRow()) + { + char map[160]; + results.FetchString(0, map, 160); + + int id = results.FetchInt(1); + int style = results.FetchInt(2); + int track = results.FetchInt(3); + + char sQueryGetWorldRecordID[256]; + FormatEx(sQueryGetWorldRecordID, 256, + "SELECT id FROM %splayertimes WHERE map = '%s' AND style = %d AND track = %d ORDER BY time LIMIT 1;", + gS_MySQLPrefix, map, style, track); + + DataPack transPack = new DataPack(); + transPack.WriteString(map); + transPack.WriteCell(id); + transPack.WriteCell(style); + transPack.WriteCell(track); + + trans.AddQuery(sQueryGetWorldRecordID, transPack); + } + + DataPack steamPack = new DataPack(); + steamPack.WriteString(sAuthID3); + steamPack.WriteCell(client); + + gH_SQL.Execute(trans, Trans_OnRecordCompare, INVALID_FUNCTION, steamPack, DBPrio_High); +} + +public void Trans_OnRecordCompare(Database db, any data, int numQueries, DBResultSet[] results, any[] queryData) +{ + DataPack pack = view_as(data); + pack.Reset(); + char sAuthID3[32]; + pack.ReadString(sAuthID3, 32); + + for(int i = 0; i < numQueries; i++) + { + DataPack hQueryPack = view_as(queryData[i]); + hQueryPack.Reset(); + char sMap[32]; + hQueryPack.ReadString(sMap, 32); + + int iRecordID = hQueryPack.ReadCell(); + int iStyle = hQueryPack.ReadCell(); + int iTrack = hQueryPack.ReadCell(); + delete hQueryPack; + + if(results[i] != null && results[i].FetchRow()) + { + int iWR = results[i].FetchInt(0); + + if(iWR == iRecordID) + { + Shavit_DeleteReplay(sMap, iStyle, iTrack); + } + } + } + + char sQueryDeleteUserTimes[256]; + FormatEx(sQueryDeleteUserTimes, 256, + "DELETE FROM %splayertimes WHERE auth = '%s';", + gS_MySQLPrefix, sAuthID3); + + gH_SQL.Query(SQL_DeleteUserTimes_Callback, sQueryDeleteUserTimes, pack, DBPrio_High); +} + +public void SQL_DeleteUserTimes_Callback(Database db, DBResultSet results, const char[] error, any data) +{ + DataPack pack = view_as(data); + pack.Reset(); + char sAuthID3[32]; + pack.ReadString(sAuthID3, 32); + + if(results == null) + { + LogError("Timer error! Failed to wipe user data (wipe | delete user times). Reason: %s", error); + + delete pack; + + return; + } + + char sQueryDeleteUsers[256]; + FormatEx(sQueryDeleteUsers, 256, "DELETE FROM %susers WHERE auth = '%s';", + gS_MySQLPrefix, sAuthID3); + + gH_SQL.Query(SQL_DeleteUserData_Callback, sQueryDeleteUsers, pack, DBPrio_High); +} + +public void SQL_DeleteUserData_Callback(Database db, DBResultSet results, const char[] error, any data) +{ + DataPack pack = view_as(data); + pack.Reset(); + char sAuthID3[32]; + pack.ReadString(sAuthID3, 32); + int client = pack.ReadCell(); + delete pack; + + if(results == null) + { + LogError("Timer error! Failed to wipe user data (wipe | delete user data, id %s). Reason: %s", error, sAuthID3); + + return; + } + + Shavit_ReloadLeaderboards(); + + Shavit_PrintToChat(client, "Finished wiping timer data for user %s%s%s.", + gS_ChatStrings.sVariable, sAuthID3, gS_ChatStrings.sText); +} + public Action Command_AutoBhop(int client, int args) { if(!IsValidClient(client)) @@ -1116,14 +1327,14 @@ public int Native_PrintToChat(Handle handler, int numParams) { PrintToServer("%s", sBuffer); - return 0; + return false; } if(!IsClientInGame(client)) { gB_StopChatSound = false; - return 0; + return false; } Handle hSayText2 = StartMessageOne("SayText2", client, USERMSG_RELIABLE|USERMSG_BLOCKHOOKS); @@ -1156,6 +1367,8 @@ public int Native_PrintToChat(Handle handler, int numParams) EndMessage(); gB_StopChatSound = false; + + return true; } public int Native_RestartTimer(Handle handler, int numParams) diff --git a/addons/sourcemod/scripting/shavit-replay.sp b/addons/sourcemod/scripting/shavit-replay.sp index 525a26f11..265b932d9 100644 --- a/addons/sourcemod/scripting/shavit-replay.sp +++ b/addons/sourcemod/scripting/shavit-replay.sp @@ -2474,6 +2474,11 @@ void GetTrackName(int client, int track, char[] output, int size) float GetReplayLength(int style, int track) { + if(gA_FrameCache[style][track].iFrameCount == 0) + { + return 0.0; + } + if(gA_FrameCache[style][track].bNewFormat) { return gA_FrameCache[style][track].fTime; From 9a27655f79468c52d7de71249b50ae33834b7853 Mon Sep 17 00:00:00 2001 From: shavit Date: Sun, 24 Feb 2019 16:23:25 +0200 Subject: [PATCH 15/27] Added the ability to delete all records per style (#667). --- addons/sourcemod/scripting/shavit-wr.sp | 65 ++++++++++++++++--- .../translations/shavit-wr.phrases.txt | 9 ++- 2 files changed, 62 insertions(+), 12 deletions(-) diff --git a/addons/sourcemod/scripting/shavit-wr.sp b/addons/sourcemod/scripting/shavit-wr.sp index 5a6fef126..94ec6c248 100644 --- a/addons/sourcemod/scripting/shavit-wr.sp +++ b/addons/sourcemod/scripting/shavit-wr.sp @@ -782,17 +782,17 @@ public Action Command_DeleteAll(int client, int args) char sInfo[8]; IntToString(i, sInfo, 8); - int records = GetTrackRecordCount(i); + int iRecords = GetTrackRecordCount(i); char sTrack[64]; GetTrackName(client, i, sTrack, 64); - if(records > 0) + if(iRecords > 0) { - Format(sTrack, 64, "%s (%T: %d)", sTrack, "WRRecord", client, records); + Format(sTrack, 64, "%s (%T: %d)", sTrack, "WRRecord", client, iRecords); } - menu.AddItem(sInfo, sTrack, (records > 0)? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED); + menu.AddItem(sInfo, sTrack, (iRecords > 0)? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED); } menu.ExitButton = true; @@ -805,9 +805,52 @@ public int MenuHandler_DeleteAll_First(Menu menu, MenuAction action, int param1, { if(action == MenuAction_Select) { - char info[16]; - menu.GetItem(param2, info, 16); - gA_WRCache[param1].iLastTrack = StringToInt(info); + char sInfo[8]; + menu.GetItem(param2, sInfo, 8); + int iTrack = gA_WRCache[param1].iLastTrack = StringToInt(sInfo); + + char sTrack[64]; + GetTrackName(param1, iTrack, sTrack, 64); + + Menu subMenu = new Menu(MenuHandler_DeleteAll_Second); + subMenu.SetTitle("%T\n ", "DeleteTrackAllStyle", param1, sTrack); + + for(int i = 0; i < gI_Styles; i++) + { + char sStyle[64]; + strcopy(sStyle, 64, gS_StyleStrings[i].sStyleName); + + IntToString(i, sInfo, 8); + + int iRecords = gI_RecordAmount[i][iTrack]; + + if(iRecords > 0) + { + Format(sStyle, 64, "%s (%T: %d)", sStyle, "WRRecord", param1, iRecords); + } + + subMenu.AddItem(sInfo, sStyle, (iRecords > 0)? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED); + } + + subMenu.ExitButton = true; + subMenu.Display(param1, 20); + } + + else if(action == MenuAction_End) + { + delete menu; + } + + return 0; +} + +public int MenuHandler_DeleteAll_Second(Menu menu, MenuAction action, int param1, int param2) +{ + if(action == MenuAction_Select) + { + char sInfo[8]; + menu.GetItem(param2, sInfo, 8); + gA_WRCache[param1].iLastStyle = StringToInt(sInfo); DeleteAllSubmenu(param1); } @@ -826,7 +869,7 @@ void DeleteAllSubmenu(int client) GetTrackName(client, gA_WRCache[client].iLastTrack, sTrack, 32); Menu menu = new Menu(MenuHandler_DeleteAll); - menu.SetTitle("%T\n ", "DeleteAllRecordsMenuTitle", client, gS_Map, sTrack); + menu.SetTitle("%T\n ", "DeleteAllRecordsMenuTitle", client, gS_Map, sTrack, gA_WRCache[client].iLastStyle); char sMenuItem[64]; @@ -866,10 +909,12 @@ public int MenuHandler_DeleteAll(Menu menu, MenuAction action, int param1, int p char sTrack[32]; GetTrackName(LANG_SERVER, gA_WRCache[param1].iLastTrack, sTrack, 32); - Shavit_LogMessage("%L - deleted all %s track records from map `%s`.", param1, sTrack, gS_Map); + Shavit_LogMessage("%L - deleted all %s track and %s style records from map `%s`.", + param1, sTrack, gS_StyleStrings[gA_WRCache[param1].iLastStyle].sStyleName, gS_Map); char sQuery[256]; - FormatEx(sQuery, 256, "DELETE FROM %splayertimes WHERE map = '%s' AND track = %d;", gS_MySQLPrefix, gS_Map, gA_WRCache[param1].iLastTrack); + FormatEx(sQuery, 256, "DELETE FROM %splayertimes WHERE map = '%s' AND style = %d AND track = %d;", + gS_MySQLPrefix, gS_Map, gA_WRCache[param1].iLastStyle, gA_WRCache[param1].iLastTrack); gH_SQL.Query(DeleteAll_Callback, sQuery, GetClientSerial(param1), DBPrio_High); } diff --git a/addons/sourcemod/translations/shavit-wr.phrases.txt b/addons/sourcemod/translations/shavit-wr.phrases.txt index b19fe1c96..528fc2cd1 100644 --- a/addons/sourcemod/translations/shavit-wr.phrases.txt +++ b/addons/sourcemod/translations/shavit-wr.phrases.txt @@ -53,8 +53,8 @@ } "DeleteAllRecordsMenuTitle" { - "#format" "{1:s},{2:s}" - "en" "Delete ALL the records for '{1}'? (Track: {2})" + "#format" "{1:s},{2:s},{3:s}" + "en" "Delete ALL the records for '{1}'? (Track: {2} | Style: {3})" } "DeleteConfirm" { @@ -107,6 +107,11 @@ { "en" "Choose a track to delete a ALL records from:" } + "DeleteTrackAllStyle" + { + "#format" "{1:s}" + "en" "Choose a style to delete all the records for ({1}):" + } // ---------- Errors ---------- // "DatabaseError" { From 08f0224759f409cace2803d4cbfb446583a9ba4d Mon Sep 17 00:00:00 2001 From: shavit Date: Sun, 24 Feb 2019 17:05:39 +0200 Subject: [PATCH 16/27] Added menu ordering for styles (#681). Also added Shavit_GetOrderedStyles ofc. --- addons/sourcemod/configs/shavit-styles.cfg | 1 + addons/sourcemod/scripting/include/shavit.inc | 13 +++- addons/sourcemod/scripting/shavit-core.sp | 51 ++++++++++++--- addons/sourcemod/scripting/shavit-replay.sp | 34 ++++++---- addons/sourcemod/scripting/shavit-stats.sp | 11 +++- addons/sourcemod/scripting/shavit-wr.sp | 63 +++++++++++-------- 6 files changed, 123 insertions(+), 50 deletions(-) diff --git a/addons/sourcemod/configs/shavit-styles.cfg b/addons/sourcemod/configs/shavit-styles.cfg index 8c4c68cb2..8f322b432 100644 --- a/addons/sourcemod/configs/shavit-styles.cfg +++ b/addons/sourcemod/configs/shavit-styles.cfg @@ -60,6 +60,7 @@ "special" "0" // For third-party modules. The core plugins will not need this setting. "specialstring" "" // For modularity. Separated with semicolon. Built-in flags: "segments". "permission" "" // Permission required. Syntax: "flag;override". For example "p;style_tas" to require the 'p' flag or the "style_tas" override. + "ordering" "0" // Ordering in menus where styles appear. If this value is not present, style ID will be used instead. } "1" diff --git a/addons/sourcemod/scripting/include/shavit.inc b/addons/sourcemod/scripting/include/shavit.inc index 44f62e725..b7faec2e2 100644 --- a/addons/sourcemod/scripting/include/shavit.inc +++ b/addons/sourcemod/scripting/include/shavit.inc @@ -156,6 +156,7 @@ enum struct stylesettings_t bool bStrafeCountD; float fRankingMultiplier; int iSpecial; + int iOrdering; } enum struct chatstrings_t @@ -1081,6 +1082,15 @@ native int Shavit_GetStyleStrings(int style, int stringtype, char[] StyleStrings */ native int Shavit_GetStyleCount(); +/** + * Gets an array with style IDs in their configured menu ordering as specified in the styles config. + * + * @param arr Reference to array to fill with style IDs. + * @param size Array size. + * @noreturn + */ +native void Shavit_GetOrderedStyles(int[] arr, int size); + /** * Saves chat related strings on string references. * @@ -1306,6 +1316,7 @@ public void __pl_shavit_SetNTVOptional() MarkNativeAsOptional("Shavit_GetHUDSettings"); MarkNativeAsOptional("Shavit_GetMapTier"); MarkNativeAsOptional("Shavit_GetMapTiers"); + MarkNativeAsOptional("Shavit_GetOrderedStyles"); MarkNativeAsOptional("Shavit_GetPerfectJumps"); MarkNativeAsOptional("Shavit_GetPlayerPB"); MarkNativeAsOptional("Shavit_GetPoints"); @@ -1337,7 +1348,6 @@ public void __pl_shavit_SetNTVOptional() MarkNativeAsOptional("Shavit_GetWRName"); MarkNativeAsOptional("Shavit_GetWRRecordID"); MarkNativeAsOptional("Shavit_GetWRTime"); - MarkNativeAsOptional("Shavit_ReloadLeaderboards"); MarkNativeAsOptional("Shavit_HasStyleAccess"); MarkNativeAsOptional("Shavit_HijackAngles"); MarkNativeAsOptional("Shavit_InsideZone"); @@ -1352,6 +1362,7 @@ public void __pl_shavit_SetNTVOptional() MarkNativeAsOptional("Shavit_PauseTimer"); MarkNativeAsOptional("Shavit_PrintToChat"); MarkNativeAsOptional("Shavit_Rankings_DeleteMap"); + MarkNativeAsOptional("Shavit_ReloadLeaderboards"); MarkNativeAsOptional("Shavit_ReloadReplay"); MarkNativeAsOptional("Shavit_ReloadReplays"); MarkNativeAsOptional("Shavit_Replay_DeleteMap"); diff --git a/addons/sourcemod/scripting/shavit-core.sp b/addons/sourcemod/scripting/shavit-core.sp index 49cab303f..657a598a5 100644 --- a/addons/sourcemod/scripting/shavit-core.sp +++ b/addons/sourcemod/scripting/shavit-core.sp @@ -131,6 +131,7 @@ ConVar sv_enablebunnyhopping = null; // timer settings bool gB_Registered = false; int gI_Styles = 0; +int gI_OrderedStyles[STYLE_LIMIT]; stylestrings_t gS_StyleStrings[STYLE_LIMIT]; stylesettings_t gA_StyleSettings[STYLE_LIMIT]; @@ -172,6 +173,7 @@ public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max CreateNative("Shavit_GetDatabase", Native_GetDatabase); CreateNative("Shavit_GetDB", Native_GetDB); CreateNative("Shavit_GetGameType", Native_GetGameType); + CreateNative("Shavit_GetOrderedStyles", Native_GetOrderedStyles); CreateNative("Shavit_GetPerfectJumps", Native_GetPerfectJumps); CreateNative("Shavit_GetStrafeCount", Native_GetStrafeCount); CreateNative("Shavit_GetStyleCount", Native_GetStyleCount); @@ -847,7 +849,7 @@ public void SQL_DeleteUserData_Callback(Database db, DBResultSet results, const } Shavit_ReloadLeaderboards(); - + Shavit_PrintToChat(client, "Finished wiping timer data for user %s%s%s.", gS_ChatStrings.sVariable, sAuthID3, gS_ChatStrings.sText); } @@ -899,14 +901,16 @@ public Action Command_Style(int client, int args) for(int i = 0; i < gI_Styles; i++) { + int iStyle = gI_OrderedStyles[i]; + char sInfo[8]; - IntToString(i, sInfo, 8); + IntToString(iStyle, sInfo, 8); char sDisplay[64]; - if(gA_StyleSettings[i].bUnranked) + if(gA_StyleSettings[iStyle].bUnranked) { - FormatEx(sDisplay, 64, "%T %s", "StyleUnranked", client, gS_StyleStrings[i].sStyleName); + FormatEx(sDisplay, 64, "%T %s", "StyleUnranked", client, gS_StyleStrings[iStyle].sStyleName); } else @@ -915,7 +919,7 @@ public Action Command_Style(int client, int args) if(gB_WR) { - time = Shavit_GetWorldRecord(i, Track_Main); + time = Shavit_GetWorldRecord(iStyle, Track_Main); } if(time > 0.0) @@ -923,16 +927,16 @@ public Action Command_Style(int client, int args) char sTime[32]; FormatSeconds(time, sTime, 32, false); - FormatEx(sDisplay, 64, "%s - WR: %s", gS_StyleStrings[i].sStyleName, sTime); + FormatEx(sDisplay, 64, "%s - WR: %s", gS_StyleStrings[iStyle].sStyleName, sTime); } else { - strcopy(sDisplay, 64, gS_StyleStrings[i].sStyleName); + strcopy(sDisplay, 64, gS_StyleStrings[iStyle].sStyleName); } } - menu.AddItem(sInfo, sDisplay, (gA_Timers[client].iStyle == i || !Shavit_HasStyleAccess(client, i))? ITEMDRAW_DISABLED:ITEMDRAW_DEFAULT); + menu.AddItem(sInfo, sDisplay, (gA_Timers[client].iStyle == iStyle || !Shavit_HasStyleAccess(client, iStyle))? ITEMDRAW_DISABLED:ITEMDRAW_DEFAULT); } // should NEVER happen @@ -1149,6 +1153,11 @@ public int Native_GetGameType(Handle handler, int numParams) return view_as(gEV_Type); } +public int Native_GetOrderedStyles(Handle handler, int numParams) +{ + return SetNativeArray(1, gI_OrderedStyles, GetNativeCell(2)); +} + public int Native_GetDatabase(Handle handler, int numParams) { return view_as(CloneHandle(gH_SQL, handler)); @@ -1848,6 +1857,7 @@ bool LoadStyles() gA_StyleSettings[i].bStrafeCountD = view_as(kv.GetNum("strafe_count_d", true)); gA_StyleSettings[i].fRankingMultiplier = kv.GetFloat("rankingmultiplier", 1.00); gA_StyleSettings[i].iSpecial = kv.GetNum("special", 0); + gA_StyleSettings[i].iOrdering = kv.GetNum("ordering", i); if(!gB_Registered && strlen(gS_StyleStrings[i].sChangeCommand) > 0) { @@ -1886,7 +1896,7 @@ bool LoadStyles() strcopy(gS_StyleOverride[i], 32, (iCount >= 2)? sText[1]:""); } - i++; + gI_OrderedStyles[i] = i++; } while(kv.GotoNextKey()); @@ -1896,6 +1906,8 @@ bool LoadStyles() gI_Styles = i; gB_Registered = true; + SortCustom1D(gI_OrderedStyles, gI_Styles, SortAscending_StyleOrder); + Call_StartForward(gH_Forwards_OnStyleConfigLoaded); Call_PushCell(gI_Styles); Call_Finish(); @@ -1903,6 +1915,27 @@ bool LoadStyles() return true; } +public int SortAscending_StyleOrder(int index1, int index2, const int[] array, any hndl) +{ + int order1 = gA_StyleSettings[index1].iOrdering; + int order2 = gA_StyleSettings[index2].iOrdering; + + if(order1 < order2) + { + return -1; + } + + else if(order1 == order2) + { + return 0; + } + + else + { + return 1; + } +} + public Action Command_StyleChange(int client, int args) { char sCommand[128]; diff --git a/addons/sourcemod/scripting/shavit-replay.sp b/addons/sourcemod/scripting/shavit-replay.sp index 265b932d9..5c18df5c8 100644 --- a/addons/sourcemod/scripting/shavit-replay.sp +++ b/addons/sourcemod/scripting/shavit-replay.sp @@ -1998,24 +1998,29 @@ public Action Command_DeleteReplay(int client, int args) Menu menu = new Menu(DeleteReplay_Callback); menu.SetTitle("%T", "DeleteReplayMenuTitle", client); + int[] styles = new int[gI_Styles]; + Shavit_GetOrderedStyles(styles, gI_Styles); + for(int i = 0; i < gI_Styles; i++) { - if(!ReplayEnabled(i)) + int iStyle = styles[i]; + + if(!ReplayEnabled(iStyle)) { continue; } for(int j = 0; j < TRACKS_SIZE; j++) { - if(gA_FrameCache[i][j].iFrameCount == 0) + if(gA_FrameCache[iStyle][j].iFrameCount == 0) { continue; } char sInfo[8]; - FormatEx(sInfo, 8, "%d;%d", i, j); + FormatEx(sInfo, 8, "%d;%d", iStyle, j); - float time = GetReplayLength(i, j); + float time = GetReplayLength(iStyle, j); char sTrack[32]; GetTrackName(client, j, sTrack, 32); @@ -2027,12 +2032,12 @@ public Action Command_DeleteReplay(int client, int args) char sTime[32]; FormatSeconds(time, sTime, 32, false); - FormatEx(sDisplay, 64, "%s (%s) - %s", gS_StyleStrings[i].sStyleName, sTrack, sTime); + FormatEx(sDisplay, 64, "%s (%s) - %s", gS_StyleStrings[iStyle].sStyleName, sTrack, sTime); } else { - FormatEx(sDisplay, 64, "%s (%s)", gS_StyleStrings[i].sStyleName, sTrack); + FormatEx(sDisplay, 64, "%s (%s)", gS_StyleStrings[iStyle].sStyleName, sTrack); } menu.AddItem(sInfo, sDisplay); @@ -2251,17 +2256,22 @@ void OpenReplaySubMenu(int client, int track) menu.AddItem("stop", sDisplay, (gA_CentralCache.iReplayStatus != Replay_Idle)? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED); } + int[] styles = new int[gI_Styles]; + Shavit_GetOrderedStyles(styles, gI_Styles); + for(int i = 0; i < gI_Styles; i++) { - if(!ReplayEnabled(i)) + int iStyle = styles[i]; + + if(!ReplayEnabled(iStyle)) { continue; } char sInfo[8]; - IntToString(i, sInfo, 8); + IntToString(iStyle, sInfo, 8); - float time = GetReplayLength(i, track); + float time = GetReplayLength(iStyle, track); char sDisplay[64]; @@ -2270,15 +2280,15 @@ void OpenReplaySubMenu(int client, int track) char sTime[32]; FormatSeconds(time, sTime, 32, false); - FormatEx(sDisplay, 64, "%s - %s", gS_StyleStrings[i].sStyleName, sTime); + FormatEx(sDisplay, 64, "%s - %s", gS_StyleStrings[iStyle].sStyleName, sTime); } else { - strcopy(sDisplay, 64, gS_StyleStrings[i].sStyleName); + strcopy(sDisplay, 64, gS_StyleStrings[iStyle].sStyleName); } - menu.AddItem(sInfo, sDisplay, (gA_FrameCache[i][track].iFrameCount > 0)? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED); + menu.AddItem(sInfo, sDisplay, (gA_FrameCache[iStyle][track].iFrameCount > 0)? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED); } if(menu.ItemCount == 0) diff --git a/addons/sourcemod/scripting/shavit-stats.sp b/addons/sourcemod/scripting/shavit-stats.sp index 4787869c2..6311054d6 100644 --- a/addons/sourcemod/scripting/shavit-stats.sp +++ b/addons/sourcemod/scripting/shavit-stats.sp @@ -462,17 +462,22 @@ public void OpenStatsMenuCallback(Database db, DBResultSet results, const char[] gS_TargetName[client], "Profile", client, gS_TargetAuth[client], "Country", client, sCountry, sLastLogin, sClearString, gS_StyleStrings[0].sStyleName, "WorldRecords", client, iWRs, sRankingString); + int[] styles = new int[gI_Styles]; + Shavit_GetOrderedStyles(styles, gI_Styles); + for(int i = 0; i < gI_Styles; i++) { - if(gA_StyleSettings[i].bUnranked) + int iStyle = styles[i]; + + if(gA_StyleSettings[iStyle].bUnranked) { continue; } char sInfo[4]; - IntToString(i, sInfo, 4); + IntToString(iStyle, sInfo, 4); - menu.AddItem(sInfo, gS_StyleStrings[i].sStyleName); + menu.AddItem(sInfo, gS_StyleStrings[iStyle].sStyleName); } // should NEVER happen diff --git a/addons/sourcemod/scripting/shavit-wr.sp b/addons/sourcemod/scripting/shavit-wr.sp index 94ec6c248..a37a7c3e4 100644 --- a/addons/sourcemod/scripting/shavit-wr.sp +++ b/addons/sourcemod/scripting/shavit-wr.sp @@ -508,13 +508,6 @@ public void SQL_UpdateWRCache_Callback(Database db, DBResultSet results, const c return; } - // resultset structure - // FIELD 0: style - // FIELD 1: id - // FIELD 2: time - sorted - // FIELD 3: name - // FIELD 4: track - // reset cache for(int i = 0; i < gI_Styles; i++) { @@ -752,15 +745,20 @@ void DeleteSubmenu(int client) Menu menu = new Menu(MenuHandler_Delete); menu.SetTitle("%T\n ", "DeleteMenuTitle", client); + int[] styles = new int[gI_Styles]; + Shavit_GetOrderedStyles(styles, gI_Styles); + for(int i = 0; i < gI_Styles; i++) { + int iStyle = styles[i]; + char sInfo[8]; - IntToString(i, sInfo, 8); + IntToString(iStyle, sInfo, 8); char sDisplay[64]; - FormatEx(sDisplay, 64, "%s (%T: %d)", gS_StyleStrings[i].sStyleName, "WRRecord", client, gI_RecordAmount[i][gA_WRCache[client].iLastTrack]); + FormatEx(sDisplay, 64, "%s (%T: %d)", gS_StyleStrings[iStyle].sStyleName, "WRRecord", client, gI_RecordAmount[iStyle][gA_WRCache[client].iLastTrack]); - menu.AddItem(sInfo, sDisplay, (gI_RecordAmount[i][gA_WRCache[client].iLastTrack] > 0)? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED); + menu.AddItem(sInfo, sDisplay, (gI_RecordAmount[iStyle][gA_WRCache[client].iLastTrack] > 0)? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED); } menu.ExitButton = true; @@ -815,14 +813,19 @@ public int MenuHandler_DeleteAll_First(Menu menu, MenuAction action, int param1, Menu subMenu = new Menu(MenuHandler_DeleteAll_Second); subMenu.SetTitle("%T\n ", "DeleteTrackAllStyle", param1, sTrack); + int[] styles = new int[gI_Styles]; + Shavit_GetOrderedStyles(styles, gI_Styles); + for(int i = 0; i < gI_Styles; i++) { + int iStyle = styles[i]; + char sStyle[64]; - strcopy(sStyle, 64, gS_StyleStrings[i].sStyleName); + strcopy(sStyle, 64, gS_StyleStrings[iStyle].sStyleName); - IntToString(i, sInfo, 8); + IntToString(iStyle, sInfo, 8); - int iRecords = gI_RecordAmount[i][iTrack]; + int iRecords = gI_RecordAmount[iStyle][iTrack]; if(iRecords > 0) { @@ -869,7 +872,7 @@ void DeleteAllSubmenu(int client) GetTrackName(client, gA_WRCache[client].iLastTrack, sTrack, 32); Menu menu = new Menu(MenuHandler_DeleteAll); - menu.SetTitle("%T\n ", "DeleteAllRecordsMenuTitle", client, gS_Map, sTrack, gA_WRCache[client].iLastStyle); + menu.SetTitle("%T\n ", "DeleteAllRecordsMenuTitle", client, gS_Map, sTrack, gS_StyleStrings[gA_WRCache[client].iLastStyle].sStyleName); char sMenuItem[64]; @@ -937,24 +940,29 @@ public Action Command_DeleteStyleRecords(int client, int args) Menu menu = new Menu(MenuHandler_DeleteStyleRecords); menu.SetTitle("%T\n ", "DeleteStyleRecordsRecordsMenuTitle", client, gS_Map); + int[] styles = new int[gI_Styles]; + Shavit_GetOrderedStyles(styles, gI_Styles); + for(int i = 0; i < gI_Styles; i++) { - if(gA_StyleSettings[i].bUnranked) + int iStyle = styles[i]; + + if(gA_StyleSettings[iStyle].bUnranked) { continue; } char sInfo[8]; - IntToString(i, sInfo, 8); + IntToString(iStyle, sInfo, 8); char sDisplay[64]; - FormatEx(sDisplay, 64, "%s (%d %T)", gS_StyleStrings[i].sStyleName, gI_RecordAmount[i], "WRRecord", client); + FormatEx(sDisplay, 64, "%s (%d %T)", gS_StyleStrings[iStyle].sStyleName, gI_RecordAmount[iStyle], "WRRecord", client); int iTotalAmount = 0; for(int j = 0; j < TRACKS_SIZE; j++) { - iTotalAmount += gI_RecordAmount[i][j]; + iTotalAmount += gI_RecordAmount[iStyle][j]; } menu.AddItem(sInfo, sDisplay, (iTotalAmount > 0)? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED); @@ -1409,32 +1417,37 @@ Action ShowWRStyleMenu(int client, int track) Menu menu = new Menu(MenuHandler_StyleChooser); menu.SetTitle("%T", "WRMenuTitle", client); + int[] styles = new int[gI_Styles]; + Shavit_GetOrderedStyles(styles, gI_Styles); + for(int i = 0; i < gI_Styles; i++) { - if(gA_StyleSettings[i].bUnranked) + int iStyle = styles[i]; + + if(gA_StyleSettings[iStyle].bUnranked) { continue; } char sInfo[8]; - IntToString(i, sInfo, 8); + IntToString(iStyle, sInfo, 8); char sDisplay[64]; - if(StrEqual(gA_WRCache[client].sClientMap, gS_Map) && gF_WRTime[i][track] > 0.0) + if(StrEqual(gA_WRCache[client].sClientMap, gS_Map) && gF_WRTime[iStyle][track] > 0.0) { char sTime[32]; - FormatSeconds(gF_WRTime[i][track], sTime, 32, false); + FormatSeconds(gF_WRTime[iStyle][track], sTime, 32, false); - FormatEx(sDisplay, 64, "%s - WR: %s", gS_StyleStrings[i].sStyleName, sTime); + FormatEx(sDisplay, 64, "%s - WR: %s", gS_StyleStrings[iStyle].sStyleName, sTime); } else { - strcopy(sDisplay, 64, gS_StyleStrings[i].sStyleName); + strcopy(sDisplay, 64, gS_StyleStrings[iStyle].sStyleName); } - menu.AddItem(sInfo, sDisplay, (gI_RecordAmount[i][track] > 0 || !StrEqual(gA_WRCache[client].sClientMap, gS_Map))? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED); + menu.AddItem(sInfo, sDisplay, (gI_RecordAmount[iStyle][track] > 0 || !StrEqual(gA_WRCache[client].sClientMap, gS_Map))? ITEMDRAW_DEFAULT:ITEMDRAW_DISABLED); } // should NEVER happen From feec3f0a2f89afba925afb92f845f8755a5b937d Mon Sep 17 00:00:00 2001 From: shavit Date: Mon, 25 Feb 2019 00:19:29 +0200 Subject: [PATCH 17/27] Removed debug message --- addons/sourcemod/scripting/shavit-hud.sp | 2 +- addons/sourcemod/scripting/shavit-misc.sp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/addons/sourcemod/scripting/shavit-hud.sp b/addons/sourcemod/scripting/shavit-hud.sp index 0dff987bf..bebb260f3 100644 --- a/addons/sourcemod/scripting/shavit-hud.sp +++ b/addons/sourcemod/scripting/shavit-hud.sp @@ -1166,7 +1166,7 @@ int AddHUDToBuffer_CSGO(int client, huddata_t data, char[] buffer, int maxlen) { if(gB_Rankings && (gI_HUD2Settings[client] & HUD2_MAPTIER) == 0) { - FormatEx(sZoneHUD, 32, "%T", "HudZoneTier", client, Shavit_GetMapTier(gS_Map)); + FormatEx(sZoneHUD, 32, "%T\n\n", "HudZoneTier", client, Shavit_GetMapTier(gS_Map)); AddHUDLine(buffer, maxlen, sZoneHUD, iLines); iLines++; } diff --git a/addons/sourcemod/scripting/shavit-misc.sp b/addons/sourcemod/scripting/shavit-misc.sp index 7585f6ea5..b71318a2b 100644 --- a/addons/sourcemod/scripting/shavit-misc.sp +++ b/addons/sourcemod/scripting/shavit-misc.sp @@ -1964,7 +1964,6 @@ void TeleportToCheckpoint(int client, int index, bool suppressMessage) gA_Targetnames.GetString(cpcache.iTargetname, sTargetname, 64); SetEntPropString(client, Prop_Data, "m_iName", sTargetname); - Shavit_PrintToChat(client, "set name %s", sTargetname); } if(cpcache.iClassname != -1) From 283bbc224fa24b9e1816c739d960ede0644cf474 Mon Sep 17 00:00:00 2001 From: shavit Date: Tue, 5 Mar 2019 00:07:26 +0200 Subject: [PATCH 18/27] Fixed deleted replays not being overwritten. --- addons/sourcemod/scripting/shavit-replay.sp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addons/sourcemod/scripting/shavit-replay.sp b/addons/sourcemod/scripting/shavit-replay.sp index 5c18df5c8..edce35c1c 100644 --- a/addons/sourcemod/scripting/shavit-replay.sp +++ b/addons/sourcemod/scripting/shavit-replay.sp @@ -323,7 +323,7 @@ void UnloadReplay(int style, int track) gA_Frames[style][track].Clear(); gA_FrameCache[style][track].iFrameCount = 0; gA_FrameCache[style][track].fTime = 0.0; - gA_FrameCache[style][track].bNewFormat = false; + gA_FrameCache[style][track].bNewFormat = true; strcopy(gA_FrameCache[style][track].sReplayName, MAX_NAME_LENGTH, "invalid"); gI_ReplayTick[style] = -1; @@ -411,7 +411,7 @@ public int Native_ReloadReplay(Handle handler, int numParams) gA_Frames[style][track] = new ArrayList(CELLS_PER_FRAME); gA_FrameCache[style][track].iFrameCount = 0; gA_FrameCache[style][track].fTime = 0.0; - gA_FrameCache[style][track].bNewFormat = false; + gA_FrameCache[style][track].bNewFormat = true; strcopy(gA_FrameCache[style][track].sReplayName, MAX_NAME_LENGTH, "invalid"); bool loaded = false; @@ -883,7 +883,7 @@ public void OnMapStart() gA_Frames[i][j] = new ArrayList(CELLS_PER_FRAME); gA_FrameCache[i][j].iFrameCount = 0; gA_FrameCache[i][j].fTime = 0.0; - gA_FrameCache[i][j].bNewFormat = false; + gA_FrameCache[i][j].bNewFormat = true; strcopy(gA_FrameCache[i][j].sReplayName, MAX_NAME_LENGTH, "invalid"); loaded = DefaultLoadReplay(i, j); From fce9ba6b11c27e2884a00114e1b1bcaa3a3ea426 Mon Sep 17 00:00:00 2001 From: shavit Date: Thu, 7 Mar 2019 01:04:46 +0200 Subject: [PATCH 19/27] Fixed !deleteall removing replays of all styles. --- addons/sourcemod/scripting/shavit-wr.sp | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/addons/sourcemod/scripting/shavit-wr.sp b/addons/sourcemod/scripting/shavit-wr.sp index a37a7c3e4..05ba93c73 100644 --- a/addons/sourcemod/scripting/shavit-wr.sp +++ b/addons/sourcemod/scripting/shavit-wr.sp @@ -1351,19 +1351,12 @@ public void DeleteAll_Callback(Database db, DBResultSet results, const char[] er return; } - for(int i = 0; i < gI_Styles; i++) - { - if(gA_StyleSettings[i].bUnranked) - { - continue; - } - Call_StartForward(gH_OnWRDeleted); - Call_PushCell(i); - Call_PushCell(-1); - Call_PushCell(gA_WRCache[client].iLastTrack); - Call_Finish(); - } + Call_StartForward(gH_OnWRDeleted); + Call_PushCell(gA_WRCache[client].iLastStyle); + Call_PushCell(-1); + Call_PushCell(gA_WRCache[client].iLastTrack); + Call_Finish(); Shavit_PrintToChat(client, "%T", "DeletedRecordsMap", client, gS_ChatStrings.sVariable, gS_Map, gS_ChatStrings.sText); } From 0fa1cbd58e3afc3c22a3a2ae5863744389f90688 Mon Sep 17 00:00:00 2001 From: shavit Date: Thu, 7 Mar 2019 01:20:50 +0200 Subject: [PATCH 20/27] Added the ability to stop playback as the requester. (#705) --- addons/sourcemod/scripting/shavit-replay.sp | 19 ++++++++++++++++--- addons/sourcemod/scripting/shavit-wr.sp | 1 - 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/addons/sourcemod/scripting/shavit-replay.sp b/addons/sourcemod/scripting/shavit-replay.sp index edce35c1c..5ee59a2ef 100644 --- a/addons/sourcemod/scripting/shavit-replay.sp +++ b/addons/sourcemod/scripting/shavit-replay.sp @@ -49,6 +49,7 @@ enum struct centralbot_cache_t int iStyle; ReplayStatus iReplayStatus; int iTrack; + int iPlaybackSerial; } enum struct replaystrings_t @@ -123,6 +124,7 @@ ConVar gCV_CentralBot = null; ConVar gCV_BotShooting = null; ConVar gCV_BotPlusUse = null; ConVar gCV_BotWeapon = null; +ConVar gCV_PlaybackCanStop = null; // timer settings int gI_Styles = 0; @@ -225,6 +227,7 @@ public void OnPluginStart() gCV_BotShooting = CreateConVar("shavit_replay_botshooting", "3", "Attacking buttons to allow for bots.\n0 - none\n1 - +attack\n2 - +attack2\n3 - both", 0, true, 0.0, true, 3.0); gCV_BotPlusUse = CreateConVar("shavit_replay_botplususe", "1", "Allow bots to use +use?", 0, true, 0.0, true, 1.0); gCV_BotWeapon = CreateConVar("shavit_replay_botweapon", "", "Choose which weapon the bot will hold.\nLeave empty to use the default.\nSet to \"none\" to have none.\nExample: weapon_usp"); + gCV_PlaybackCanStop = CreateConVar("shavit_replay_pbcanstop", "1", "Allow players to stop playback if they requested it?", 0, true, 0.0, true, 1.0); gCV_CentralBot.AddChangeHook(OnConVarChanged); @@ -752,6 +755,7 @@ public void OnMapStart() gA_CentralCache.iStyle = -1; gA_CentralCache.iReplayStatus = Replay_Idle; gA_CentralCache.iTrack = Track_Main; + gA_CentralCache.iPlaybackSerial = 0; gB_ForciblyStopped = false; @@ -1818,6 +1822,8 @@ bool IsWallBetween(float pos1[3], float pos2[3], int bot) public Action Timer_EndReplay(Handle Timer, any data) { + gA_CentralCache.iPlaybackSerial = 0; + if(gCV_CentralBot.BoolValue && gB_ForciblyStopped) { gB_ForciblyStopped = false; @@ -2169,7 +2175,7 @@ public Action Command_Replay(int client, int args) return Plugin_Handled; } - if(CheckCommandAccess(client, "sm_deletereplay", ADMFLAG_RCON)) + if(CanStopCentral(client)) { char arg[8]; GetCmdArg(1, arg, 8); @@ -2248,7 +2254,7 @@ void OpenReplaySubMenu(int client, int track) Menu menu = new Menu(MenuHandler_ReplaySubmenu); menu.SetTitle("%T (%s)\n ", "CentralReplayTitle", client, sTrack); - if(CheckCommandAccess(client, "sm_deletereplay", ADMFLAG_RCON)) + if(CanStopCentral(client)) { char sDisplay[64]; FormatEx(sDisplay, 64, "%T", "CentralReplayStop", client); @@ -2312,7 +2318,7 @@ public int MenuHandler_ReplaySubmenu(Menu menu, MenuAction action, int param1, i char info[16]; menu.GetItem(param2, info, 16); - if(StrEqual(info, "stop")) + if(StrEqual(info, "stop") && CanStopCentral(param1)) { StopCentralReplay(param1); OpenReplaySubMenu(param1, gI_Track[param1]); @@ -2339,6 +2345,7 @@ public int MenuHandler_ReplaySubmenu(Menu menu, MenuAction action, int param1, i gI_ReplayTick[style] = 0; gA_CentralCache.iStyle = style; gA_CentralCache.iTrack = gI_Track[param1]; + gA_CentralCache.iPlaybackSerial = GetClientSerial(param1); gI_ReplayBotClient[style] = gA_CentralCache.iClient; gRS_ReplayStatus[style] = gA_CentralCache.iReplayStatus = Replay_Start; TeleportToStart(gA_CentralCache.iClient, style, gI_Track[param1]); @@ -2365,6 +2372,11 @@ public int MenuHandler_ReplaySubmenu(Menu menu, MenuAction action, int param1, i return 0; } +bool CanStopCentral(int client) +{ + return CheckCommandAccess(client, "sm_deletereplay", ADMFLAG_RCON) || (gCV_PlaybackCanStop.BoolValue && GetClientSerial(client) == gA_CentralCache.iPlaybackSerial); +} + void TeleportToStart(int client, int style, int track) { if(gA_FrameCache[style][track].iFrameCount == 0) @@ -2399,6 +2411,7 @@ void StopCentralReplay(int client) gF_StartTick[style] = -65535.0; gA_CentralCache.iStyle = 0; gB_ForciblyStopped = true; + gA_CentralCache.iPlaybackSerial = 0; if(gA_CentralCache.iClient != -1) { diff --git a/addons/sourcemod/scripting/shavit-wr.sp b/addons/sourcemod/scripting/shavit-wr.sp index 05ba93c73..bcee5b7c9 100644 --- a/addons/sourcemod/scripting/shavit-wr.sp +++ b/addons/sourcemod/scripting/shavit-wr.sp @@ -1351,7 +1351,6 @@ public void DeleteAll_Callback(Database db, DBResultSet results, const char[] er return; } - Call_StartForward(gH_OnWRDeleted); Call_PushCell(gA_WRCache[client].iLastStyle); Call_PushCell(-1); From 8f26d7be0e7c4f207d606b14117ec497f4aef6ed Mon Sep 17 00:00:00 2001 From: shavit Date: Thu, 7 Mar 2019 01:30:49 +0200 Subject: [PATCH 21/27] Added cooldown on playback/stop for regular users. --- addons/sourcemod/scripting/shavit-replay.sp | 22 ++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/addons/sourcemod/scripting/shavit-replay.sp b/addons/sourcemod/scripting/shavit-replay.sp index 5ee59a2ef..2316fee57 100644 --- a/addons/sourcemod/scripting/shavit-replay.sp +++ b/addons/sourcemod/scripting/shavit-replay.sp @@ -95,6 +95,7 @@ bool gB_Button[MAXPLAYERS+1]; int gI_PlayerFrames[MAXPLAYERS+1]; ArrayList gA_PlayerFrames[MAXPLAYERS+1]; int gI_Track[MAXPLAYERS+1]; +float gF_LastInteraction[MAXPLAYERS+1]; bool gB_Late = false; @@ -125,6 +126,7 @@ ConVar gCV_BotShooting = null; ConVar gCV_BotPlusUse = null; ConVar gCV_BotWeapon = null; ConVar gCV_PlaybackCanStop = null; +ConVar gCV_PlaybackCooldown = null; // timer settings int gI_Styles = 0; @@ -228,6 +230,7 @@ public void OnPluginStart() gCV_BotPlusUse = CreateConVar("shavit_replay_botplususe", "1", "Allow bots to use +use?", 0, true, 0.0, true, 1.0); gCV_BotWeapon = CreateConVar("shavit_replay_botweapon", "", "Choose which weapon the bot will hold.\nLeave empty to use the default.\nSet to \"none\" to have none.\nExample: weapon_usp"); gCV_PlaybackCanStop = CreateConVar("shavit_replay_pbcanstop", "1", "Allow players to stop playback if they requested it?", 0, true, 0.0, true, 1.0); + gCV_PlaybackCooldown = CreateConVar("shavit_replay_pbcooldown", "10.0", "Cooldown in seconds to apply for players between each playback they request/stop.\nDoes not apply to RCON admins.", 0, true, 0.0); gCV_CentralBot.AddChangeHook(OnConVarChanged); @@ -1822,6 +1825,13 @@ bool IsWallBetween(float pos1[3], float pos2[3], int bot) public Action Timer_EndReplay(Handle Timer, any data) { + int client = GetClientFromSerial(gA_CentralCache.iPlaybackSerial); + + if(client != 0) + { + gF_LastInteraction[client] = GetEngineTime(); + } + gA_CentralCache.iPlaybackSerial = 0; if(gCV_CentralBot.BoolValue && gB_ForciblyStopped) @@ -2346,6 +2356,7 @@ public int MenuHandler_ReplaySubmenu(Menu menu, MenuAction action, int param1, i gA_CentralCache.iStyle = style; gA_CentralCache.iTrack = gI_Track[param1]; gA_CentralCache.iPlaybackSerial = GetClientSerial(param1); + gF_LastInteraction[param1] = GetEngineTime(); gI_ReplayBotClient[style] = gA_CentralCache.iClient; gRS_ReplayStatus[style] = gA_CentralCache.iReplayStatus = Replay_Start; TeleportToStart(gA_CentralCache.iClient, style, gI_Track[param1]); @@ -2374,7 +2385,10 @@ public int MenuHandler_ReplaySubmenu(Menu menu, MenuAction action, int param1, i bool CanStopCentral(int client) { - return CheckCommandAccess(client, "sm_deletereplay", ADMFLAG_RCON) || (gCV_PlaybackCanStop.BoolValue && GetClientSerial(client) == gA_CentralCache.iPlaybackSerial); + return (CheckCommandAccess(client, "sm_deletereplay", ADMFLAG_RCON) || + (gCV_PlaybackCanStop.BoolValue && + GetClientSerial(client) == gA_CentralCache.iPlaybackSerial && + GetEngineTime() - gF_LastInteraction[client] > gCV_PlaybackCooldown.FloatValue)); } void TeleportToStart(int client, int style, int track) @@ -2404,6 +2418,12 @@ void StopCentralReplay(int client) } int style = gA_CentralCache.iStyle; + int player = GetClientFromSerial(gA_CentralCache.iPlaybackSerial); + + if(player != 0) + { + gF_LastInteraction[player] = GetEngineTime(); + } gRS_ReplayStatus[style] = gA_CentralCache.iReplayStatus = Replay_Idle; gI_ReplayTick[style] = 0; From 9bcc6878d42544818aa799b463ff77502eebf748 Mon Sep 17 00:00:00 2001 From: shavit Date: Thu, 7 Mar 2019 01:48:07 +0200 Subject: [PATCH 22/27] Fixed replays breaking unexpectedly at certain interactions. Example of breakage: 1. Request playback. 2. When the replay playback is about to end (the delay where the bot idles in the end zone), stop the playback. 3. Request playback ASAP. --- addons/sourcemod/scripting/shavit-replay.sp | 29 +++++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/addons/sourcemod/scripting/shavit-replay.sp b/addons/sourcemod/scripting/shavit-replay.sp index 2316fee57..98d25fd5a 100644 --- a/addons/sourcemod/scripting/shavit-replay.sp +++ b/addons/sourcemod/scripting/shavit-replay.sp @@ -90,6 +90,7 @@ float gF_StartTick[STYLE_LIMIT]; ReplayStatus gRS_ReplayStatus[STYLE_LIMIT]; framecache_t gA_FrameCache[STYLE_LIMIT][TRACKS_SIZE]; bool gB_ForciblyStopped = false; +Handle gH_ReplayTimers[STYLE_LIMIT]; bool gB_Button[MAXPLAYERS+1]; int gI_PlayerFrames[MAXPLAYERS+1]; @@ -452,7 +453,9 @@ public int Native_ReloadReplay(Handle handler, int numParams) { gI_ReplayTick[style] = 0; gRS_ReplayStatus[style] = Replay_Start; - CreateTimer((gCV_ReplayDelay.FloatValue / 2.0), Timer_StartReplay, style, TIMER_FLAG_NO_MAPCHANGE); + + delete gH_ReplayTimers[style]; + gH_ReplayTimers[style] = CreateTimer((gCV_ReplayDelay.FloatValue / 2.0), Timer_StartReplay, style, TIMER_FLAG_NO_MAPCHANGE); } } @@ -748,6 +751,13 @@ public void OnMapStart() SetFailState("Could not load the replay bots' configuration file. Make sure it exists (addons/sourcemod/configs/shavit-replay.cfg) and follows the proper syntax!"); } + // VERY RARE CASE + // this is required to not cause replays to break if we change map before playback starts, after it is requested + for(int i = 0; i < STYLE_LIMIT; i++) + { + gH_ReplayTimers[i] = null; + } + if(gB_Late) { Shavit_OnStyleConfigLoaded(-1); @@ -905,7 +915,9 @@ public void OnMapStart() { gI_ReplayTick[i] = 0; gRS_ReplayStatus[i] = Replay_Start; - CreateTimer((gCV_ReplayDelay.FloatValue / 2.0), Timer_StartReplay, i, TIMER_FLAG_NO_MAPCHANGE); + + delete gH_ReplayTimers[i]; + gH_ReplayTimers[i] = CreateTimer((gCV_ReplayDelay.FloatValue / 2.0), Timer_StartReplay, i, TIMER_FLAG_NO_MAPCHANGE); } } } @@ -1668,7 +1680,8 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3 gI_ReplayTick[style] = 0; gRS_ReplayStatus[style] = gA_CentralCache.iReplayStatus = Replay_End; - CreateTimer((gCV_ReplayDelay.FloatValue / 2.0), Timer_EndReplay, style, TIMER_FLAG_NO_MAPCHANGE); + delete gH_ReplayTimers[style]; + gH_ReplayTimers[style] = CreateTimer((gCV_ReplayDelay.FloatValue / 2.0), Timer_EndReplay, style, TIMER_FLAG_NO_MAPCHANGE); return Plugin_Changed; } @@ -1825,6 +1838,8 @@ bool IsWallBetween(float pos1[3], float pos2[3], int bot) public Action Timer_EndReplay(Handle Timer, any data) { + gH_ReplayTimers[data] = null; + int client = GetClientFromSerial(gA_CentralCache.iPlaybackSerial); if(client != 0) @@ -1851,7 +1866,8 @@ public Action Timer_EndReplay(Handle Timer, any data) { gRS_ReplayStatus[data] = Replay_Start; - CreateTimer((gCV_ReplayDelay.FloatValue / 2.0), Timer_StartReplay, data, TIMER_FLAG_NO_MAPCHANGE); + delete gH_ReplayTimers[data]; + gH_ReplayTimers[data] = CreateTimer((gCV_ReplayDelay.FloatValue / 2.0), Timer_StartReplay, data, TIMER_FLAG_NO_MAPCHANGE); } else @@ -1865,6 +1881,8 @@ public Action Timer_EndReplay(Handle Timer, any data) public Action Timer_StartReplay(Handle Timer, any data) { + gH_ReplayTimers[data] = null; + if(gRS_ReplayStatus[data] == Replay_Running || (gCV_CentralBot.BoolValue && gB_ForciblyStopped)) { return Plugin_Stop; @@ -2366,7 +2384,8 @@ public int MenuHandler_ReplaySubmenu(Menu menu, MenuAction action, int param1, i UpdateReplayInfo(gA_CentralCache.iClient, style, time, gI_Track[param1]); - CreateTimer((gCV_ReplayDelay.FloatValue / 2.0), Timer_StartReplay, style, TIMER_FLAG_NO_MAPCHANGE); + delete gH_ReplayTimers[style]; + gH_ReplayTimers[style] = CreateTimer((gCV_ReplayDelay.FloatValue / 2.0), Timer_StartReplay, style, TIMER_FLAG_NO_MAPCHANGE); } } From fdf65ca1880e8213bf180962332677c3441fc489 Mon Sep 17 00:00:00 2001 From: shavit Date: Thu, 7 Mar 2019 03:23:01 +0200 Subject: [PATCH 23/27] Improved replay smoothness. * Fixed for illogical teleports. * Improved replay smoothness when teleporting/landing. * Removed pointless TR. --- addons/sourcemod/scripting/shavit-replay.sp | 51 +++++---------------- 1 file changed, 12 insertions(+), 39 deletions(-) diff --git a/addons/sourcemod/scripting/shavit-replay.sp b/addons/sourcemod/scripting/shavit-replay.sp index 98d25fd5a..f3be66edc 100644 --- a/addons/sourcemod/scripting/shavit-replay.sp +++ b/addons/sourcemod/scripting/shavit-replay.sp @@ -89,6 +89,7 @@ ArrayList gA_Frames[STYLE_LIMIT][TRACKS_SIZE]; float gF_StartTick[STYLE_LIMIT]; ReplayStatus gRS_ReplayStatus[STYLE_LIMIT]; framecache_t gA_FrameCache[STYLE_LIMIT][TRACKS_SIZE]; + bool gB_ForciblyStopped = false; Handle gH_ReplayTimers[STYLE_LIMIT]; @@ -1682,6 +1683,7 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3 delete gH_ReplayTimers[style]; gH_ReplayTimers[style] = CreateTimer((gCV_ReplayDelay.FloatValue / 2.0), Timer_EndReplay, style, TIMER_FLAG_NO_MAPCHANGE); + gA_CentralCache.iPlaybackSerial = 0; return Plugin_Changed; } @@ -1731,9 +1733,9 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3 MoveType movetype = gA_Frames[style][track].Get(gI_ReplayTick[style], 7); - if(movetype == MOVETYPE_LADDER) + if(movetype == MOVETYPE_LADDER || (movetype == MOVETYPE_WALK && (iReplayFlags & FL_ONGROUND) > 0)) { - mt = MOVETYPE_LADDER; + mt = movetype; } } @@ -1743,33 +1745,16 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3 MakeVectorFromPoints(vecCurrentPosition, vecPosition, vecVelocity); ScaleVector(vecVelocity, gF_Tickrate); - if(gI_ReplayTick[style] > 1) + if(gI_ReplayTick[style] > 1 && + // replay is going above 50k speed, just teleport at this point + (GetVectorLength(vecVelocity) > 50000.0 || + // bot is on ground.. if the distance between the previous position is much bigger (1.5x) than the expected according + // to the bot's velocity, teleport to avoid sync issues + (mt == MOVETYPE_WALK && GetVectorDistance(vecCurrentPosition, vecPosition) > GetVectorLength(vecVelocity) / gF_Tickrate * 1.5))) { - float vecLastPosition[3]; - vecLastPosition[0] = gA_Frames[style][track].Get(gI_ReplayTick[style] - 1, 0); - vecLastPosition[1] = gA_Frames[style][track].Get(gI_ReplayTick[style] - 1, 1); - vecLastPosition[2] = gA_Frames[style][track].Get(gI_ReplayTick[style] - 1, 2); - - // fix for replay not syncing - if(GetVectorDistance(vecLastPosition, vecCurrentPosition) >= 100.0 && IsWallBetween(vecLastPosition, vecCurrentPosition, client)) - { - TeleportEntity(client, vecPosition, NULL_VECTOR, NULL_VECTOR); - - return Plugin_Handled; - } - - #if defined DEBUG - PrintToChatAll("vecVelocity: %.02f | dist %.02f", GetVectorLength(vecVelocity), GetVectorDistance(vecLastPosition, vecPosition) * gF_Tickrate); - #endif + TeleportEntity(client, vecPosition, vecAngles, NULL_VECTOR); - if(GetVectorLength(vecVelocity) / (GetVectorDistance(vecLastPosition, vecPosition) * gF_Tickrate) > 2.0) - { - MakeVectorFromPoints(vecLastPosition, vecPosition, vecVelocity); - ScaleVector(vecVelocity, gF_Tickrate); - TeleportEntity(client, vecLastPosition, vecAngles, vecVelocity); - - return Plugin_Changed; - } + return Plugin_Changed; } TeleportEntity(client, NULL_VECTOR, vecAngles, vecVelocity); @@ -1824,18 +1809,6 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3 return Plugin_Continue; } -public bool Filter_Clients(int entity, int contentsMask, any data) -{ - return (1 <= entity <= MaxClients && entity != data); -} - -bool IsWallBetween(float pos1[3], float pos2[3], int bot) -{ - TR_TraceRayFilter(pos1, pos2, MASK_SOLID, RayType_EndPoint, Filter_Clients, bot); - - return !TR_DidHit(); -} - public Action Timer_EndReplay(Handle Timer, any data) { gH_ReplayTimers[data] = null; From 1d5c63c595051cb827b327b7955126b427659d60 Mon Sep 17 00:00:00 2001 From: shavit Date: Thu, 7 Mar 2019 03:38:31 +0200 Subject: [PATCH 24/27] Made transition to last frame of replay much smoother. --- addons/sourcemod/scripting/shavit-replay.sp | 71 ++++----------------- 1 file changed, 11 insertions(+), 60 deletions(-) diff --git a/addons/sourcemod/scripting/shavit-replay.sp b/addons/sourcemod/scripting/shavit-replay.sp index f3be66edc..06b0ab1b1 100644 --- a/addons/sourcemod/scripting/shavit-replay.sp +++ b/addons/sourcemod/scripting/shavit-replay.sp @@ -781,13 +781,6 @@ public void OnMapStart() return; } - bot_quota = FindConVar((gEV_Type != Engine_TF2)? "bot_quota":"tf_bot_quota"); - - if(bot_quota != null) - { - bot_quota.Flags &= ~FCVAR_NOTIFY; - } - char sTempMap[PLATFORM_MAX_PATH]; FormatEx(sTempMap, PLATFORM_MAX_PATH, "maps/%s.nav", gS_Map); @@ -810,60 +803,18 @@ public void OnMapStart() if(bot_controllable != null) { bot_controllable.BoolValue = false; - delete bot_controllable; - } - - ConVar bot_stop = FindConVar("bot_stop"); - - if(bot_stop != null) - { - bot_stop.BoolValue = true; - delete bot_stop; - } - - ConVar bot_quota_mode = FindConVar((gEV_Type != Engine_TF2)? "bot_quota_mode":"tf_bot_quota_mode"); - - if(bot_quota_mode != null) - { - bot_quota_mode.SetString("normal"); - delete bot_quota_mode; - } - - ConVar mp_limitteams = FindConVar("mp_limitteams"); - - if(mp_limitteams != null) - { - mp_limitteams.IntValue = 0; - delete mp_limitteams; - } - - ConVar bot_join_after_player = FindConVar((gEV_Type != Engine_TF2)? "bot_join_after_player":"tf_bot_join_after_player"); - - if(bot_join_after_player != null) - { - bot_join_after_player.BoolValue = false; - delete bot_join_after_player; - } - - ConVar bot_chatter = FindConVar("bot_chatter"); - - if(bot_chatter != null) - { - bot_chatter.SetString("off"); - delete bot_chatter; - } - - ConVar bot_zombie = FindConVar("bot_zombie"); - - if(bot_zombie != null) - { - bot_zombie.BoolValue = true; - delete bot_zombie; } - ConVar mp_autoteambalance = FindConVar("mp_autoteambalance"); - mp_autoteambalance.BoolValue = false; - delete mp_autoteambalance; + FindConVar((gEV_Type != Engine_TF2)? "bot_quota":"tf_bot_quota").Flags &= ~FCVAR_NOTIFY; + FindConVar("bot_stop").Flags &= ~FCVAR_CHEAT; + FindConVar("bot_stop").BoolValue = true; + FindConVar((gEV_Type != Engine_TF2)? "bot_quota_mode":"tf_bot_quota_mode").SetString("normal"); + FindConVar("mp_limitteams").IntValue = 0; + FindConVar((gEV_Type != Engine_TF2)? "bot_join_after_player":"tf_bot_join_after_player").BoolValue = false; + FindConVar("bot_chatter").SetString("off"); + FindConVar("bot_flipout").BoolValue = true; + FindConVar("bot_zombie").BoolValue = true; + FindConVar("mp_autoteambalance").BoolValue = false; ServerCommand((gEV_Type != Engine_TF2)? "bot_kick":"tf_bot_kick all"); @@ -1670,7 +1621,7 @@ public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3 float vecVelocity[3]; MakeVectorFromPoints(vecCurrentPosition, vecPosition, vecVelocity); ScaleVector(vecVelocity, gF_Tickrate); - TeleportEntity(client, NULL_VECTOR, vecAngles, vecVelocity); + TeleportEntity(client, NULL_VECTOR, NULL_VECTOR, vecVelocity); } return Plugin_Changed; From 4c9a969d3a59314f34dbb57625fe2f4e158a030f Mon Sep 17 00:00:00 2001 From: shavit Date: Fri, 8 Mar 2019 09:00:00 +0200 Subject: [PATCH 25/27] Added far more extensive logging for single record deletion. --- addons/sourcemod/scripting/shavit-wr.sp | 190 +++++++++++++++++------- 1 file changed, 138 insertions(+), 52 deletions(-) diff --git a/addons/sourcemod/scripting/shavit-wr.sp b/addons/sourcemod/scripting/shavit-wr.sp index bcee5b7c9..63cd09b4c 100644 --- a/addons/sourcemod/scripting/shavit-wr.sp +++ b/addons/sourcemod/scripting/shavit-wr.sp @@ -1108,8 +1108,9 @@ public int MenuHandler_Delete(Menu menu, MenuAction action, int param1, int para { char info[16]; menu.GetItem(param2, info, 16); + gA_WRCache[param1].iLastStyle = StringToInt(info); - OpenDelete(param1, StringToInt(info)); + OpenDelete(param1); UpdateLeaderboards(); } @@ -1122,25 +1123,17 @@ public int MenuHandler_Delete(Menu menu, MenuAction action, int param1, int para return 0; } -void OpenDelete(int client, int style) +void OpenDelete(int client) { char sQuery[512]; + FormatEx(sQuery, 512, "SELECT p.id, u.name, p.time, p.jumps FROM %splayertimes p JOIN %susers u ON p.auth = u.auth WHERE map = '%s' AND style = %d AND track = %d ORDER BY time ASC, date ASC LIMIT 1000;", + gS_MySQLPrefix, gS_MySQLPrefix, gS_Map, gA_WRCache[client].iLastStyle, gA_WRCache[client].iLastTrack); - FormatEx(sQuery, 512, "SELECT p.id, u.name, p.time, p.jumps FROM %splayertimes p JOIN %susers u ON p.auth = u.auth WHERE map = '%s' AND style = %d AND track = %d ORDER BY time ASC, date ASC LIMIT 1000;", gS_MySQLPrefix, gS_MySQLPrefix, gS_Map, style, gA_WRCache[client].iLastTrack); - DataPack datapack = new DataPack(); - datapack.WriteCell(GetClientSerial(client)); - datapack.WriteCell(style); - - gH_SQL.Query(SQL_OpenDelete_Callback, sQuery, datapack, DBPrio_High); + gH_SQL.Query(SQL_OpenDelete_Callback, sQuery, GetClientSerial(client), DBPrio_High); } -public void SQL_OpenDelete_Callback(Database db, DBResultSet results, const char[] error, DataPack data) +public void SQL_OpenDelete_Callback(Database db, DBResultSet results, const char[] error, any data) { - data.Reset(); - int client = GetClientFromSerial(data.ReadCell()); - int style = data.ReadCell(); - delete data; - if(results == null) { LogError("Timer (WR OpenDelete) SQL query failed. Reason: %s", error); @@ -1148,13 +1141,17 @@ public void SQL_OpenDelete_Callback(Database db, DBResultSet results, const char return; } + int client = GetClientFromSerial(data); + if(client == 0) { return; } + int iStyle = gA_WRCache[client].iLastStyle; + Menu menu = new Menu(OpenDelete_Handler); - menu.SetTitle("%t", "ListClientRecords", gS_Map, gS_StyleStrings[style].sStyleName); + menu.SetTitle("%t", "ListClientRecords", gS_Map, gS_StyleStrings[iStyle].sStyleName); int iCount = 0; @@ -1200,10 +1197,10 @@ public int OpenDelete_Handler(Menu menu, MenuAction action, int param1, int para { if(action == MenuAction_Select) { - char info[16]; - menu.GetItem(param2, info, 16); + char sInfo[16]; + menu.GetItem(param2, sInfo, 16); - int id = StringToInt(info); + int id = StringToInt(sInfo); if(id != -1) { @@ -1234,9 +1231,9 @@ void OpenDeleteMenu(int client, int id) FormatEx(sMenuItem, 64, "%T", "MenuResponseYesSingle", client); - char info[16]; - IntToString(id, info, 16); - menu.AddItem(info, sMenuItem); + char sInfo[16]; + IntToString(id, sInfo, 16); + menu.AddItem(sInfo, sMenuItem); for(int i = 1; i <= GetRandomInt(1, 3); i++) { @@ -1252,9 +1249,10 @@ public int DeleteConfirm_Handler(Menu menu, MenuAction action, int param1, int p { if(action == MenuAction_Select) { - char info[16]; - menu.GetItem(param2, info, 16); - int iRecordID = StringToInt(info); + char sInfo[16]; + menu.GetItem(param2, sInfo, 16); + + int iRecordID = StringToInt(sInfo); if(iRecordID == -1) { @@ -1263,35 +1261,11 @@ public int DeleteConfirm_Handler(Menu menu, MenuAction action, int param1, int p return 0; } - for(int i = 0; i < gI_Styles; i++) - { - if(gA_StyleSettings[i].bUnranked) - { - continue; - } - - for(int j = 0; j < TRACKS_SIZE; j++) - { - if(gI_WRRecordID[i][j] != iRecordID) - { - continue; - } - - Call_StartForward(gH_OnWRDeleted); - Call_PushCell(i); - Call_PushCell(iRecordID); - Call_PushCell(j); - Call_Finish(); - } - } - - // TODO: display record details here (map name, player name/authid, time, rank on map) without dropping threaded queries - Shavit_LogMessage("%L - deleted record id %d.", param1, iRecordID); - char sQuery[256]; - FormatEx(sQuery, 256, "DELETE FROM %splayertimes WHERE id = %d;", gS_MySQLPrefix, iRecordID); + FormatEx(sQuery, 256, "SELECT u.auth, u.name, p.map, p.time, p.sync, p.perfs, p.jumps, p.strafes, p.id, p.date FROM %susers u LEFT JOIN %splayertimes p ON u.auth = p.auth WHERE p.id = %d;", + gS_MySQLPrefix, gS_MySQLPrefix, iRecordID); - gH_SQL.Query(DeleteConfirm_Callback, sQuery, GetClientSerial(param1), DBPrio_High); + gH_SQL.Query(GetRecordDetails_Callback, sQuery, GetClientSerial(param1), DBPrio_High); } else if(action == MenuAction_End) @@ -1302,8 +1276,101 @@ public int DeleteConfirm_Handler(Menu menu, MenuAction action, int param1, int p return 0; } +public void GetRecordDetails_Callback(Database db, DBResultSet results, const char[] error, any data) +{ + if(results == null) + { + LogError("Timer (WR GetRecordDetails) SQL query failed. Reason: %s", error); + + return; + } + + int client = GetClientFromSerial(data); + + if(client == 0) + { + return; + } + + if(results.FetchRow()) + { + char sAuthID[32]; + results.FetchString(0, sAuthID, 32); + + char sName[MAX_NAME_LENGTH]; + results.FetchString(1, sName, MAX_NAME_LENGTH); + + char sMap[160]; + results.FetchString(2, sMap, 160); + + float fTime = results.FetchFloat(3); + float fSync = results.FetchFloat(4); + float fPerfectJumps = results.FetchFloat(5); + + int iJumps = results.FetchInt(6); + int iStrafes = results.FetchInt(7); + int iRecordID = results.FetchInt(8); + int iTimestamp = results.FetchInt(9); + + int iStyle = gA_WRCache[client].iLastStyle; + int iTrack = gA_WRCache[client].iLastTrack; + bool bWRDeleted = (gI_WRRecordID[iStyle][iTrack] == iRecordID); + + // that's a big datapack ya yeet + DataPack hPack = new DataPack(); + hPack.WriteCell(GetClientSerial(client)); + hPack.WriteString(sAuthID); + hPack.WriteString(sName); + hPack.WriteString(sMap); + hPack.WriteCell(fTime); + hPack.WriteCell(fSync); + hPack.WriteCell(fPerfectJumps); + hPack.WriteCell(iJumps); + hPack.WriteCell(iStrafes); + hPack.WriteCell(iRecordID); + hPack.WriteCell(iTimestamp); + hPack.WriteCell(iStyle); + hPack.WriteCell(iTrack); + hPack.WriteCell(bWRDeleted); + + char sQuery[256]; + FormatEx(sQuery, 256, "DELETE FROM %splayertimes WHERE id = %d;", + gS_MySQLPrefix, iRecordID); + + gH_SQL.Query(DeleteConfirm_Callback, sQuery, hPack, DBPrio_High); + } +} + public void DeleteConfirm_Callback(Database db, DBResultSet results, const char[] error, any data) { + DataPack hPack = view_as(data); + hPack.Reset(); + + int iSerial = hPack.ReadCell(); + + char sAuthID[32]; + hPack.ReadString(sAuthID, 32); + + char sName[MAX_NAME_LENGTH]; + hPack.ReadString(sName, MAX_NAME_LENGTH); + + char sMap[160]; + hPack.ReadString(sMap, 160); + + float fTime = view_as(hPack.ReadCell()); + float fSync = view_as(hPack.ReadCell()); + float fPerfectJumps = view_as(hPack.ReadCell()); + + int iJumps = hPack.ReadCell(); + int iStrafes = hPack.ReadCell(); + int iRecordID = hPack.ReadCell(); + int iTimestamp = hPack.ReadCell(); + int iStyle = hPack.ReadCell(); + int iTrack = hPack.ReadCell(); + + bool bWRDeleted = view_as(hPack.ReadCell()); + delete hPack; + if(results == null) { LogError("Timer (WR DeleteConfirm) SQL query failed. Reason: %s", error); @@ -1311,6 +1378,15 @@ public void DeleteConfirm_Callback(Database db, DBResultSet results, const char[ return; } + if(bWRDeleted) + { + Call_StartForward(gH_OnWRDeleted); + Call_PushCell(iStyle); + Call_PushCell(iRecordID); + Call_PushCell(iTrack); + Call_Finish(); + } + UpdateWRCache(); for(int i = 1; i <= MaxClients; i++) @@ -1318,7 +1394,17 @@ public void DeleteConfirm_Callback(Database db, DBResultSet results, const char[ OnClientPutInServer(i); } - int client = GetClientFromSerial(data); + int client = GetClientFromSerial(iSerial); + + char sTrack[32]; + GetTrackName(LANG_SERVER, iTrack, sTrack, 32); + + char sDate[32]; + FormatTime(sDate, 32, "%Y-%m-%d %H:%M:%S", iTimestamp); + + // above the client == 0 so log doesn't get lost if admin disconnects between deleting record and query execution + Shavit_LogMessage("%L - deleted record. Runner: %s (%s) | Map: %s | Style: %s | Track: %s | Time: %.2f (%s) | Strafes: %d (%.1f%%) | Jumps: %d (%.1f%%) | Run date: %s | Record ID: %d", + client, sName, sAuthID, sMap, gS_StyleStrings[iStyle].sStyleName, sTrack, fTime, (bWRDeleted)? "WR":"not WR", iStrafes, fSync, iJumps, fPerfectJumps, sDate, iRecordID); if(client == 0) { From bf3767481223bd72ce0e5d4da0cd445f18168e55 Mon Sep 17 00:00:00 2001 From: shavit Date: Fri, 8 Mar 2019 09:37:37 +0200 Subject: [PATCH 26/27] Implemented Shavit_ChangeClientStyle forward. --- addons/sourcemod/scripting/include/shavit.inc | 13 +++++++++ addons/sourcemod/scripting/shavit-core.sp | 29 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/addons/sourcemod/scripting/include/shavit.inc b/addons/sourcemod/scripting/include/shavit.inc index b7faec2e2..2663f46b4 100644 --- a/addons/sourcemod/scripting/include/shavit.inc +++ b/addons/sourcemod/scripting/include/shavit.inc @@ -653,6 +653,18 @@ native void Shavit_Replay_DeleteMap(const char[] map); */ native void Shavit_Rankings_DeleteMap(const char[] map); +/** + * Changes a player's bhop style. + * + * @param client Client index. + * @param style Style. + * @param force Ignore style permissions. + * @param manual Is it a manual style change? (Was it caused by user interaction?) + * @param noforward Bypasses the call to `Shavit_OnStyleChanged`. + * @return False if failed due to lack of access, true otherwise. + */ +native bool Shavit_ChangeClientStyle(int client, int style, bool force = false, bool manual = false, bool noforward = false); + /** * Finishes the map for a player, with their current timer stats. * Will not teleport the player to anywhere, it's handled inside the mapzones plugin. @@ -1301,6 +1313,7 @@ public SharedPlugin __pl_shavit = #if !defined REQUIRE_PLUGIN public void __pl_shavit_SetNTVOptional() { + MarkNativeAsOptional("Shavit_ChangeClientStyle"); MarkNativeAsOptional("Shavit_DeleteReplay"); MarkNativeAsOptional("Shavit_FinishMap"); MarkNativeAsOptional("Shavit_ForceHUDUpdate"); diff --git a/addons/sourcemod/scripting/shavit-core.sp b/addons/sourcemod/scripting/shavit-core.sp index 657a598a5..63990a3a5 100644 --- a/addons/sourcemod/scripting/shavit-core.sp +++ b/addons/sourcemod/scripting/shavit-core.sp @@ -164,6 +164,7 @@ public Plugin myinfo = public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) { + CreateNative("Shavit_ChangeClientStyle", Native_ChangeClientStyle); CreateNative("Shavit_FinishMap", Native_FinishMap); CreateNative("Shavit_GetBhopStyle", Native_GetBhopStyle); CreateNative("Shavit_GetChatStrings", Native_GetChatStrings); @@ -1234,6 +1235,34 @@ public int Native_StopTimer(Handle handler, int numParams) Call_Finish(); } +public int Native_ChangeClientStyle(Handle handler, int numParams) +{ + int client = GetNativeCell(1); + int style = GetNativeCell(2); + bool force = view_as(GetNativeCell(3)); + bool manual = view_as(GetNativeCell(4)); + bool noforward = view_as(GetNativeCell(5)); + + if(force || Shavit_HasStyleAccess(client, style)) + { + if(noforward) + { + gA_Timers[client].iStyle = style; + + UpdateStyleSettings(client); + } + + else + { + CallOnStyleChanged(client, gA_Timers[client].iStyle, style, manual); + } + + return true; + } + + return false; +} + public int Native_FinishMap(Handle handler, int numParams) { int client = GetNativeCell(1); From 15c67cc317464255d1f5c37ae75ddf37f41a79f0 Mon Sep 17 00:00:00 2001 From: shavit Date: Fri, 8 Mar 2019 10:57:36 +0200 Subject: [PATCH 27/27] Implemented Shavit_OnRankAssigned forward. --- addons/sourcemod/scripting/include/shavit.inc | 12 ++++++ addons/sourcemod/scripting/shavit-rankings.sp | 38 +++++++++++++++---- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/addons/sourcemod/scripting/include/shavit.inc b/addons/sourcemod/scripting/include/shavit.inc index 2663f46b4..fdd4b7f94 100644 --- a/addons/sourcemod/scripting/include/shavit.inc +++ b/addons/sourcemod/scripting/include/shavit.inc @@ -547,6 +547,18 @@ forward void Shavit_OnWorstRecord(int client, int style, float time, int jumps, */ forward void Shavit_OnTierAssigned(const char[] map, int tier); +/** + * Gets called when the server acknowledges the client's ranking status. + * It is called after OnClientPostAdminCheck and at forced rank recalculations. + * + * @param client Client index. + * @param rank Client's rank. (0 if unranked or unassigned) + * @param points Client's points. (0.0 if unranked or unassigned) + * @param first True if the forward is called after the initial connection, false if it is caused by recalculation. + * @noreturn + */ +forward void Shavit_OnRankAssigned(int client, int rank, float points, bool first); + /** * Called when replay playback starts. * diff --git a/addons/sourcemod/scripting/shavit-rankings.sp b/addons/sourcemod/scripting/shavit-rankings.sp index 20fa4a1c1..f77c6542f 100644 --- a/addons/sourcemod/scripting/shavit-rankings.sp +++ b/addons/sourcemod/scripting/shavit-rankings.sp @@ -73,6 +73,7 @@ int gI_RankedPlayers = 0; Menu gH_Top100Menu = null; Handle gH_Forwards_OnTierAssigned = null; +Handle gH_Forwards_OnRankAssigned = null; // Timer settings. chatstrings_t gS_ChatStrings; @@ -127,6 +128,7 @@ public void OnAllPluginsLoaded() public void OnPluginStart() { gH_Forwards_OnTierAssigned = CreateGlobalForward("Shavit_OnTierAssigned", ET_Event, Param_String, Param_Cell); + gH_Forwards_OnRankAssigned = CreateGlobalForward("Shavit_OnRankAssigned", ET_Event, Param_Cell, Param_Cell, Param_Cell, Param_Cell); RegConsoleCmd("sm_tier", Command_Tier, "Prints the map's tier to chat."); RegConsoleCmd("sm_maptier", Command_Tier, "Prints the map's tier to chat. (sm_tier alias)"); @@ -387,7 +389,7 @@ public void OnClientPostAdminCheck(int client) { if(!IsFakeClient(client)) { - UpdatePlayerRank(client); + UpdatePlayerRank(client, true); } } @@ -705,7 +707,7 @@ public void Trans_OnRecalcSuccess(Database db, any data, int numQueries, DBResul { if(IsClientInGame(i) && IsClientAuthorized(i)) { - UpdatePlayerRank(i); + UpdatePlayerRank(i, false); } } @@ -780,7 +782,9 @@ void UpdateAllPoints() #endif char sQuery[128]; - FormatEx(sQuery, 128, "UPDATE %susers SET points = GetWeightedPoints(auth);", gS_MySQLPrefix); + FormatEx(sQuery, 128, "UPDATE %susers SET points = GetWeightedPoints(auth);", + gS_MySQLPrefix); + gH_SQL.Query(SQL_UpdateAllPoints_Callback, sQuery); } @@ -794,7 +798,7 @@ public void SQL_UpdateAllPoints_Callback(Database db, DBResultSet results, const } } -void UpdatePlayerRank(int client) +void UpdatePlayerRank(int client, bool first) { gI_Rank[client] = 0; gF_Points[client] = 0.0; @@ -809,12 +813,23 @@ void UpdatePlayerRank(int client) FormatEx(sQuery, 512, "SELECT p.points, COUNT(*) rank FROM %susers u JOIN (SELECT points FROM %susers WHERE auth = '%s' LIMIT 1) p WHERE u.points >= p.points LIMIT 1;", gS_MySQLPrefix, gS_MySQLPrefix, sAuthID); - gH_SQL.Query(SQL_UpdatePlayerRank_Callback, sQuery, GetClientSerial(client), DBPrio_Low); + DataPack hPack = new DataPack(); + hPack.WriteCell(GetClientSerial(client)); + hPack.WriteCell(first); + + gH_SQL.Query(SQL_UpdatePlayerRank_Callback, sQuery, hPack, DBPrio_Low); } } public void SQL_UpdatePlayerRank_Callback(Database db, DBResultSet results, const char[] error, any data) { + DataPack hPack = view_as(data); + hPack.Reset(); + + int iSerial = hPack.ReadCell(); + bool bFirst = view_as(hPack.ReadCell()); + delete hPack; + if(results == null) { LogError("Timer (rankings, update player rank) error! Reason: %s", error); @@ -822,7 +837,7 @@ public void SQL_UpdatePlayerRank_Callback(Database db, DBResultSet results, cons return; } - int client = GetClientFromSerial(data); + int client = GetClientFromSerial(iSerial); if(client == 0) { @@ -833,13 +848,22 @@ public void SQL_UpdatePlayerRank_Callback(Database db, DBResultSet results, cons { gF_Points[client] = results.FetchFloat(0); gI_Rank[client] = (gF_Points[client] > 0.0)? results.FetchInt(1):0; + + Call_StartForward(gH_Forwards_OnRankAssigned); + Call_PushCell(client); + Call_PushCell(gI_Rank[client]); + Call_PushCell(gF_Points[client]); + Call_PushCell(bFirst); + Call_Finish(); } } void UpdateRankedPlayers() { char sQuery[512]; - FormatEx(sQuery, 512, "SELECT COUNT(*) count FROM %susers WHERE points > 0.0;", gS_MySQLPrefix); + FormatEx(sQuery, 512, "SELECT COUNT(*) count FROM %susers WHERE points > 0.0;", + gS_MySQLPrefix); + gH_SQL.Query(SQL_UpdateRankedPlayers_Callback, sQuery, 0, DBPrio_High); }