LagFix — Performance optimization plugin for MC 1.8+
A lightweight performance plugin with no NMS and no reflection: the same .jar works from MC 1.8 up to modern versions (on 1.13+ it loads as a "legacy" plugin, which is normal and expected).
Modules
| Module | What it does | Default |
|---|---|---|
| ClearLag | Removes ground items, arrows and XP orbs every X seconds, with configurable warnings. | On (every 5 min) |
| Mob Limiter | Cancels spawns when the chunk already holds too many mobs; extra limit around spawners. | On (40/chunk) |
| Item Merge | Merges equal ground items into a single stack (very useful on 1.8, which barely merges). | On |
| Redstone Limiter | Freezes a chunk's redstone when it exceeds the update limit (anti lag machines). | On (300/5s) |
| TPS Auto-action | If TPS drops below the threshold repeatedly, alerts admins and runs a cleanup. | On (<15 TPS) |
| Adaptive Mode | Control loop that gradually tightens/relaxes every limit based on real TPS (AIMD-style). | On |
| Plugin Guardian | Instruments other plugins' listeners: measures event time, counts errors, detects task leaks, self-heals slow/failing listeners and can quarantine offenders. | On |
| Statistics | Stores TPS, online players, mobs, entities, chunks and memory in SQLite or MySQL. | On (every 60s) |
| Hopper Limiter | Experimental: spaces out hopper transfers. | Off |
| TPS Monitor | Computes TPS by measuring real time between ticks (no NMS). | Always on |
Built-in protections: never removes entities with custom names, tamed animals, ridden mobs, or items managed by other plugins (holograms, etc.).
Building
Requirements: JDK 8–17 and Maven 3.6+
The jar ends up at target/LagFix-1.3.0.jar. Copy it into the server's plugins/ folder and restart.
Commands
| Command | Description | Permission |
|---|---|---|
/lag |
Help | — |
/lag tps |
Current TPS, 1m/5m/15m averages, memory, adaptive stress and next cleanup | lagfix.tps |
/lag status |
Chunks, entities, items and mobs per world | lagfix.status |
/lag stats [n] |
Last n saved history samples (max 20) | lagfix.stats |
/lag plugins [restore] |
Per-plugin event usage, errors, tasks, mitigations and quarantine | lagfix.plugins |
/lag clear |
Immediate manual cleanup | lagfix.clear |
/lag reload |
Reloads the config and restarts the modules | lagfix.reload |
Aliases: /lagfix, /perf. Master permission: lagfix.admin (OP by default). The lagfix.notify permission receives automatic alerts.
Configuration
Everything is tuned in plugins/LagFix/config.yml (each module has its own enabled). Messages accept & color codes and the placeholders {seconds}, {count}, {tps}, {plugin}, {event}, {ms}, {n} and {stress}. Disabled modules register no listeners, so they cost nothing.
Adaptive Mode
Traditional anti-lag plugins use fixed limits and one "panic action" when a threshold is crossed. LagFix instead runs a closed-loop regulator: it keeps a stress level (0–100%) computed from the real TPS, and every module scales its limits continuously by querying it live:
- The per-chunk and per-spawner mob limits shrink down to 40% of their value.
- The per-chunk redstone budget shrinks down to 25%.
- The item-merge radius grows up to ×2 (more aggressive merging).
- The next scheduled cleanup is moved up to 30s (warnings preserved).
Dynamics inspired by network congestion control (AIMD): stress rises fast proportionally to the TPS deficit and falls slowly as the server recovers, with hysteresis on alerts (enters at 50%, announces exit at 10%) to avoid spam. Everything returns to normal on its own — no admin intervention. Watch the stress and live factors with /lag tps.
It coexists with the TPS auto-action: adaptive mode is the "cruise control" and the auto-action is the "emergency brake".
Plugin Guardian
Instead of linking against specific plugins' APIs (which would tie the jar to external dependencies), LagFix uses Bukkit's own plugin API (HandlerList, RegisteredListener, BukkitScheduler) to watch over and correct the problems of every other plugin generically:
- Event profiling: replaces each foreign listener with a measuring proxy that preserves priority and behavior. Every minute you know how many ms of tick time each plugin spent, its worst event and how many errors it threw (
/lag plugins). Cost per event: 2 clock reads and 1 atomic add. - Task-leak detector: if a plugin endlessly piles up pending scheduler tasks (a classic bug that sinks TPS), admins are alerted with the culprit's name.
- Quarantine (optional, off by default): automatically unregisters the specific listener exceeding the configured cost — the rest of the plugin keeps running. Reversible with
/lag plugins restore.
Self-healing (soft mitigation)
Rather than removing a misbehaving listener, the guardian can replace its behavior so the plugin keeps working in a degraded but functional mode — and recovers on its own:
- Throttle (off by default): a slow listener receives only 1 of every N events. After several calm windows it is automatically restored to full speed. A safety list (
never-throttle-events) protects critical events likeBlockBreakEventfrom ever being throttled — skipped events are invisible to the plugin, so be careful on protection-critical servers. - Circuit breaker (on by default): after 50 consecutive errors, the failing listener is paused (its calls skipped — no more console stack-trace spam) and automatically retried after 60s. If the probe call succeeds, it closes again by itself and the console logs the recovery.
Both states are visible in /lag plugins ([throttled], [paused: errors], plus a skipped-events counter) and can be cleared at once with /lag plugins restore.
Design safety: LagFix never measures itself, the originals are fully restored on reload or disable, and it reacts to PluginEnableEvent/PluginDisableEvent to instrument hot-loaded plugins and purge unloaded ones.
Statistics history
Every minute (configurable) the plugin stores one sample with: TPS, online players, living mobs, total entities, loaded chunks and JVM memory. Records are pruned automatically after keep-days days.
- SQLite (default): local database at
plugins/LagFix/stats.db. Zero configuration. - MySQL (optional): set
stats.storage.typetoMYSQLand fill in host, port, database, user and password.
Nothing to install: the SQLite and MySQL drivers already ship inside the Spigot jar.
Threading design: data is collected on the main thread (the Bukkit API is not thread-safe), but the SQL reads/writes run on async threads, so the database can never touch the TPS — even if MySQL is slow or down.
About memory: the JVM-wide used/max memory is stored. Java cannot measure per-plugin memory because every plugin shares the same heap; you need a profiler like spark for that.
Extra advice (outside the plugin)
A plugin helps, but the biggest win on 1.8 comes from the server's own configuration:
spigot.yml
view-distance: 6(or lower with many players)entity-activation-range: animals 16, monsters 24, misc 8mob-spawn-range: 4merge-radius: item 3.5, exp 5.0hopper-transfer: 16andhopper-check: 16(the proper way to optimize hoppers)max-entity-collisions: 2
bukkit.yml
spawn-limits: monsters 50, animals 12, ambient 3ticks-per: monster-spawns: 4
JVM: allocate a reasonable amount of RAM (-Xms = -Xmx) and avoid oversizing; on Java 8, Aikar's G1GC flags work well.
Technical notes
- Compiled against
spigot-api 1.8.8with Java 8: guarantees no later API is used. - TPS is computed by a task every 20 ticks measuring real time (portable to any version).
plugin.ymlintentionally omitsapi-versionso the plugin loads on 1.8–1.12 as well as 1.13+.- The hopper module is off by default because cancelling
InventoryMoveItemEventcauses retries;spigot.ymlis the right tool for that. - The guardian is the most invasive module (it manipulates the event bus): test it outside production first, and keep
quarantine.autoandthrottle.enabledoff unless you need them.