Skip to content
Monitoring & Integrations

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.

EndpointReturns
GET /api/xantilag/statusFeature toggles, TPS (1m / 5m / 15m), entity count, loaded chunks, online players, low-TPS mode flag
GET /api/xantilag/chunks/topTop 10 most expensive loaded chunks with full breakdown
GET /api/xantilag/history?minutes=NRolling TPS / MSPT samples, plus the lowest TPS and peak MSPT over the window
GET /api/xantilag/reportThe full diagnostic snapshot as JSON
GET /api/xantilag/statsClearlag timing and stacker configuration
  • Token auth — Same Bearer token as XCore's web panel
  • Rate limiting30 requests 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();
}
MemberAnswers
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
PerformanceLevelChangeEventFired 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

PlaceholderDescription
%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