Skip to content

[perf] Stagger stack-hack scans to smooth second-update load#3213

Open
Xekep wants to merge 3 commits intoPryaxis:general-develfrom
TerraZ-Team:pr/micro-perf-stack-scan-stagger
Open

[perf] Stagger stack-hack scans to smooth second-update load#3213
Xekep wants to merge 3 commits intoPryaxis:general-develfrom
TerraZ-Team:pr/micro-perf-stack-scan-stagger

Conversation

@Xekep
Copy link
Contributor

@Xekep Xekep commented Feb 27, 2026

Summary

  • add per-player stack-scan timestamp state
  • schedule stack checks at 5s intervals instead of every second per player
  • initialize timestamps with player-index offset to spread work

Scope

  • focused changes in TSPlayer and TShock.OnSecondUpdate`n- no unrelated file changes

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.
@hakusaro
Copy link
Member

@greptile review

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 27, 2026

Greptile Summary

Implements performance optimization by throttling stack-hack detection from every second to 5-second intervals per player, with staggered initialization to distribute load.

Key Changes:

  • Added LastStackDetectionCheck timestamp field to track per-player scan timing
  • Initialized timestamp with -(index % 5) offset to stagger checks across players
  • Wrapped stack detection in 5-second interval check before running expensive HasHackedItemStacks()

Critical Issue:

  • player.IsBeingDisabled() and player.Disable() were moved outside the ServerSideCharacter conditional (line 1235-1238), changing behavior from original code where this only ran when !Main.ServerSideCharacter || (Main.ServerSideCharacter && player.IsLoggedIn)

Confidence Score: 2/5

  • Logic bug breaks ServerSideCharacter behavior - requires fix before merge
  • The performance optimization logic is sound, but moving player.Disable() outside the ServerSideCharacter check is a critical behavior change that affects when players get disabled
  • TShockAPI/TShock.cs requires immediate attention - the IsBeingDisabled() block must be moved back inside the ServerSideCharacter conditional

Important Files Changed

Filename Overview
TShockAPI/TSPlayer.cs Added LastStackDetectionCheck field and staggered initialization using index % 5 to distribute stack-scan load
TShockAPI/TShock.cs Throttled stack detection to 5s intervals but moved player.Disable() outside ServerSideCharacter check, changing behavior

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[OnSecondUpdate fires every second] --> B{ServerSideCharacter check}
    B -->|Pass: !SSC OR SSC && IsLoggedIn| C{Check: 5s elapsed since LastStackDetectionCheck?}
    B -->|Fail| E
    C -->|Yes: stackCheckDue = true| D[Update LastStackDetectionCheck = Now]
    C -->|No: < 5s elapsed| E
    D --> F{Has ignorestackhackdetection permission?}
    F -->|No| G[Run HasHackedItemStacks]
    F -->|Yes: skip check| E
    G --> H[Set IsDisabledForStackDetection]
    H --> E{IsBeingDisabled?}
    E -->|Yes| I[Call player.Disable]
    E -->|No| J[End]
    I --> J
    
    style C fill:#90EE90
    style E fill:#FFB6C6
    style I fill:#FFB6C6
Loading

Last reviewed commit: a6c6918

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +1235 to 1238
if (player.IsBeingDisabled())
{
player.Disable(flags: flags);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

player.Disable() now runs outside the ServerSideCharacter check, changing original behavior. Previously only disabled when !Main.ServerSideCharacter || (Main.ServerSideCharacter && player.IsLoggedIn), now runs unconditionally.

Move this block inside the closing brace at line 1233:

Suggested change
if (player.IsBeingDisabled())
{
player.Disable(flags: flags);
}
}
if (player.IsBeingDisabled())
{
player.Disable(flags: flags);
}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants