From c28e0b2dd64a38df5bb5fdae64c458e1ed495049 Mon Sep 17 00:00:00 2001 From: Xekep Date: Thu, 26 Feb 2026 15:58:58 +0300 Subject: [PATCH 1/3] Stagger stack-hack scans to smooth second-update load Run stack detection checks only when the per-player interval is due, then evaluate permissions, instead of checking permissions every second. Initialize LastStackDetectionCheck with a per-index offset so expensive stack scans are distributed across seconds rather than spiking simultaneously. --- TShockAPI/TSPlayer.cs | 2 ++ TShockAPI/TShock.cs | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs index b4dbdd28e..f6d1bc620 100644 --- a/TShockAPI/TSPlayer.cs +++ b/TShockAPI/TSPlayer.cs @@ -1528,6 +1528,7 @@ public TSPlayer(int index) Group = Group.DefaultGroup; IceTiles = new List(); AwaitingResponse = new Dictionary>(); + LastStackDetectionCheck = DateTime.UtcNow.AddSeconds(-(index % 5)); } /// @@ -1542,6 +1543,7 @@ protected TSPlayer(String playerName) FakePlayer = new Player { name = playerName, whoAmI = -1 }; Group = Group.DefaultGroup; AwaitingResponse = new Dictionary>(); + LastStackDetectionCheck = DateTime.UtcNow; if (playerName == "All" || playerName == "Server") FinishedHandshake = true; //Hot fix for the all player object not getting packets like TimeSet, etc because they have no state and finished handshake will always be false. diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index 28cf03c1f..ff31a7c78 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -1221,10 +1221,16 @@ private void OnSecondUpdate() if (!Main.ServerSideCharacter || (Main.ServerSideCharacter && player.IsLoggedIn)) { - if (!player.HasPermission(Permissions.ignorestackhackdetection)) + var stackCheckDue = (DateTime.UtcNow - player.LastStackDetectionCheck).TotalSeconds >= 5; + if (stackCheckDue) { - player.IsDisabledForStackDetection = player.HasHackedItemStacks(shouldWarnPlayer: true); + player.LastStackDetectionCheck = DateTime.UtcNow; + if (!player.HasPermission(Permissions.ignorestackhackdetection)) + { + player.IsDisabledForStackDetection = player.HasHackedItemStacks(shouldWarnPlayer: true); + } } + } if (player.IsBeingDisabled()) { From 54513348d828901cd28fa202bf620c44e8251997 Mon Sep 17 00:00:00 2001 From: Xekep Date: Fri, 27 Feb 2026 06:01:45 +0300 Subject: [PATCH 2/3] Add stack-check timestamp state for staggered scans --- TShockAPI/TSPlayer.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/TShockAPI/TSPlayer.cs b/TShockAPI/TSPlayer.cs index f6d1bc620..b2af3fc3b 100644 --- a/TShockAPI/TSPlayer.cs +++ b/TShockAPI/TSPlayer.cs @@ -273,6 +273,11 @@ public Group Group /// public DateTime LastPvPTeamChange; + /// + /// The last time stack-hack detection was run for this player. + /// + public DateTime LastStackDetectionCheck; + /// /// Temp points for use in regions and other plugins. /// From a6c69182b474dd07dc57125fbbebf736066a4f2f Mon Sep 17 00:00:00 2001 From: Xekep Date: Fri, 27 Feb 2026 06:05:51 +0300 Subject: [PATCH 3/3] Fix OnSecondUpdate brace flow in staggered stack-scan branch --- TShockAPI/TShock.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/TShockAPI/TShock.cs b/TShockAPI/TShock.cs index ff31a7c78..3d25229b8 100644 --- a/TShockAPI/TShock.cs +++ b/TShockAPI/TShock.cs @@ -1232,10 +1232,9 @@ private void OnSecondUpdate() } } - if (player.IsBeingDisabled()) - { - player.Disable(flags: flags); - } + if (player.IsBeingDisabled()) + { + player.Disable(flags: flags); } } }