Monitoring & Integrations
Performance Monitor
Watches TPS and MSPT, and applies graduated optimization levels. A level triggers when either signal crosses its threshold.
Why MSPT matters: a server can show a flawless 20 TPS while spending 45 ms of every 50 ms tick. It is on time, with no headroom left — one entity spike away from dropping. A TPS-only monitor sees nothing at all until it is already too late.
monitor:
enabled: true
check-interval: 5
startup-delay: 60
levels:
- tps: 18.0
mspt: 45.0
actions:
reduce-mob-spawn-rate: true
- tps: 16.0
mspt: 50.0
actions:
reduce-view-distance: true
reduce-simulation-distance: true
reduce-activation-range: true
view-distance: 6
simulation-distance: 6
activation-range: 16
tracking-range: 32
reduce-activation-range is the cheapest lever here and the first worth pulling: entities past that distance stop being ticked and tracked. Nothing is deleted, nobody sees a frozen mob at close range, and the ranges are restored the moment the server recovers.
Startup grace period
TPS and MSPT are meaningless while worlds load and plugins start, so startup-delay holds evaluation back for that long. Measurements are still taken during the grace period — only the actions wait. That way the first evaluation is based on a settled reading rather than on values still converging from their starting point.
Folia has no single tick loop to average, and some forks report nothing. When the tick time cannot be measured, it is shown as an estimate derived from the tick rate and never triggers a level on its own — thresholds then rest on TPS alone. Before 1.1.1 an unmeasurable tick time counted as 50 ms, above the first level's 45 ms threshold, so that level stayed on permanently on a healthy server.
Sustained degradation alert
The levels react to the instant; this reacts to the duration. One notification fires when the server stays under threshold for long enough, to staff and to Discord:
monitor:
alert:
enabled: true
tps: 12.0
mspt: 50.0
duration-seconds: 300
Load forecast
Acting when the server is already struggling is acting late. The monitor keeps a trend over the last sixty samples, fits a slope to it, and warns when the current direction would cross the first optimization level within the horizon.
monitor:
# Nothing is measured for this long after a start, while chunks and plugins settle.
startup-delay: 180
forecast:
enabled: true
horizon-seconds: 30
The warning is a warning, not an action: nothing is throttled on a forecast alone.
History
TPS and MSPT are already measured every second; keeping them costs a float pair per sample. A full day at one sample per ten seconds is 8 640 entries, held in a fixed ring that never grows. It feeds GET /api/xantilag/history and the dashboard charts.
Distances are never written directly by the monitor. It declares a constraint, and a single component resolves the smallest applicable value between the baseline, the AFK state and the monitor — which is why a recovery can no longer pull an AFK player back up to full view distance.
Diagnostics
The web dashboard answers the first question anyone asks when the server stutters: not "is a limiter switched on" but what is this server actually carrying right now.
- TPS and MSPT with their five-minute peaks, charted over the retained history
- Memory, uptime, players online, active optimization level
- Per-world chunk, entity and tile-entity counts
- The heaviest loaded chunks, with coordinates
Collection is asynchronous and bounded — chunks are read on their own region thread, capped in number, and a timeout releases the result with whatever came back. Opening the page on a struggling server does not make things worse.
Console Logging
A detector that fires several times a minute buries everything else in the log. Each one is silent unless you name it, and its line goes to the debug channel instead.
console-logging:
chunk-load-watcher: false
anti-chunkloader: false
redstone-clock: false
lag-machine: false
afk-machine: false
chunk-limits: false
stuck-chunks: false
These control the console only. What staff are told in-game is separate, and each detector has its own notify-staff setting, so you can keep a quiet console and still be told in chat. Turn a line on while you are tuning a threshold, then turn it back off.
With debug: true every one of these is printed regardless, which is what the debug channel is for.
Discord Notifications
Performance levels, sustained alerts, cleanups, chunk limits, redstone clocks and AFK machines can be pushed to a webhook.
discord:
enabled: false
webhook-url: ""
username: "XAntiLag"
rate-limit-per-minute: 20
events:
performance-level: true
performance-alert: true
clearlag: false
chunk-limit: true
redstone-clock: true
afk-machine: true
Nothing is hardcoded. Every title, body, embed colour and footer lives in lang/<code>.yml under the discord-* keys, with %placeholders% the plugin fills in. Rewrite them, translate them, or reduce them to one line — the plugin only decides when to send.
What goes out is capped by a sliding one-minute quota. Beyond the quota, messages are dropped rather than queued: a burst of events during a lag spike must not become a backlog that arrives long after anyone could act on it.
Sending itself is XCore's job, shared with every addon. A webhook that answers "too many requests" is left alone for as long as Discord asks, and the message goes out afterwards instead of being lost.
Web Dashboard
XAntiLag registers a module with XCore's web panel exposing JSON endpoints for remote monitoring.
Four pages: Status, Performance (TPS and MSPT history), Load (entities and loaded chunks over time — TPS says the server is struggling, these say what with) and Heatmap, which draws the busiest world from above. The heaviest-chunks table answers which one; it never shows that forty of them are the same farm. Coordinates are grouped until the grid fits, so clusters are visible at a glance.
| Endpoint | Returns |
|---|---|
GET /api/xantilag/status | Feature toggles, TPS (1m / 5m / 15m), entity count, loaded chunks, online players, low-TPS mode flag |
GET /api/xantilag/chunks/top | Top 10 most expensive loaded chunks with full breakdown |
GET /api/xantilag/history?minutes=N | Rolling TPS / MSPT samples, plus the lowest TPS and peak MSPT over the window |
GET /api/xantilag/report | The full diagnostic snapshot as JSON |
GET /api/xantilag/stats | Clearlag timing and stacker configuration |
- Token auth — Same Bearer token as XCore's web panel
- Rate limiting —
30requests per minute per IP - Folia-safe — Chunk endpoint samples each chunk on its owning region thread
Developer API
Every anti-lag measure in one plugin fights the same problem alone. The plugins that actually generate the load — cosmetics spraying particles, animated menus redrawing on a timer, schedulers hammering — have no idea the server is struggling, so they keep going exactly when they should not.
repositories {
maven { url 'https://jitpack.io' }
}
dependencies {
compileOnly 'com.github.Xyness:XAntiLag-API:1.1.0'
}
// State, at any moment, from any thread
if (XAntiLagProvider.isRegistered() && XAntiLagProvider.get().isUnderLoad()) {
return; // skip the particle burst
}
// Or react only when it changes
@EventHandler
public void onLoad(PerformanceLevelChangeEvent event) {
particlesEnabled = event.isRecovery();
}
| Member | Answers |
|---|---|
currentTps() / currentMspt() | The smoothed readings |
activeLevel() | 0 when healthy, 1..n as configured levels trigger |
isUnderLoad() | Whether any level is applied |
spawnRate() | Percentage of natural spawns currently allowed |
isAfk(uuid) / afkCount() | AFK state, based on real movement |
PerformanceLevelChangeEvent | Fired on every level change and on recovery |
compileOnly on purpose: the classes are provided at runtime by XAntiLag itself. Shading them into your own jar gives you a different class of the same name, and a listener registered on it never fires. Sources: github.com/Xyness/XAntiLag-API.
PlaceholderAPI
| Placeholder | Description |
|---|---|
%xantilag_afk% | Returns (AFK) if the player is AFK, empty otherwise |
%xantilag_isAfk% | Returns yes or no |
%xantilag_afk_time% | How long the player has been away |
%xantilag_afk_count% | Number of players currently AFK |
%xantilag_tps% | Current smoothed TPS |
%xantilag_mspt% | Current smoothed MSPT |
%xantilag_clearlag% | Time remaining until next scheduled clearlag |