Перейти к содержимому
Mineforgian

NeuroLag

A smart, resource-aware optimization plugin that dynamically adjusts Mob AI based on server TPS and RAM to ensure a lag-free SMP experience

Загрузки
423
Подписчики
4
Обновлён
2 июня 2026 г.
Лицензия
Apache-2.0

Опубликован 7 марта 2026 г.

NeuroLag Icon

NeuroLag

Smart TPS-aware mob AI optimizer for Paper 1.21+

Modrinth Paper Java License

Protect your TPS before the lag even starts — then quietly undo everything when the server recovers.

📥 Download🐛 Report a Bug📄 Changelog


📖 Table of Contents

  • ✨ Features
  • 🔁 How It Works
  • 📦 Requirements
  • 🚀 Installation
  • ⌨️ Commands & Permissions
  • 🔧 Configuration
  • 🌐 Web Dashboard
  • 🔗 Multi-Server Sync
  • 🛡️ Protected Zones
  • 🗂️ Config Profiles
  • 💾 Backup System
  • 🧩 Developer API
  • 🔍 Troubleshooting
  • ❓ FAQ
  • 📄 Credits

✨ Features

🧠 Intelligent TPS State Machine

NeuroLag continuously samples TPS, CPU load, heap usage, player count, and predictive trend data to decide which of three states to apply per world:

State Default Trigger Effect
NORMAL TPS ≥ 18.0 No restrictions; full AI restored
MEDIUM TPS < 18.0 Follow-range scaled, pathfinding limited, tick-throttle on
CRITICAL TPS < 15.0 Full AI disable, spawn suppression, smart culling

All thresholds are configurable per-world and can be overridden by config profiles. A hysteresis buffer (default 0.5 TPS) prevents oscillation at the boundary.


⚡ 31 Optimization Features

F1 — CPU Throttle Penalty

Monitors JVM CPU usage. When usage exceeds the configured threshold (default 80%), a 1.5 TPS penalty is applied to the effective TPS calculation, triggering stricter mob optimizations before the server thread becomes saturated.

F2 — Region-Based Pathfinding Cutoff

Divides each world into configurable regions. Mobs beyond the pathfinding distance threshold (disable-pathfinding-distance-chunks: 8) have their FOLLOW_RANGE attribute zeroed, eliminating expensive A* pathfinding for mobs no player will ever see.

F3 — Chunk-Based AI Toggle

Mobs outside a configurable chunk radius from any player (distance-chunks: 4) have their AI disabled entirely during CRITICAL state. Mobs within range always retain full AI regardless of server state.

F4 — Velocity Freeze

Distant AI-disabled mobs have their velocity zeroed to prevent passive drift. Configurable minimum chunk distance (freeze-distance-chunks: 6).

F5 — Spawn Suppression

During MEDIUM and CRITICAL states, monster and animal spawn limits are reduced (monster-limit: 30, animal-limit: 10) to slow mob population growth while the server is already under load.

F6 — Smart Culling

When the per-world entity count exceeds max-entities-per-world during CRITICAL state, the lowest-priority mobs are removed. Supports three culling strategies:

Strategy Behaviour
FAR_FROM_PLAYER Remove mobs furthest from any player first
GROUP Remove mob types that have the most instances
RANDOM Shuffle and remove

Protected-zone mobs and named / tamed mobs (if whitelisted) are never culled.

F7 — Tick Throttling

During MEDIUM state, non-priority mobs have their AI ticked only once every N game ticks (ticks-per-ai-tick: 4) instead of every tick. This halves or quarters AI cost without fully disabling mobs.

F8 — Mob Weight System

Each entity type is assigned a weight score. Culling prioritizes heaviest entities first. Fully configurable (zombies.yml-style block in features.yml).

Entity Default Weight
Bat 0.3
Bee 0.5
Zombie 1.0
Skeleton 1.2
Creeper 1.5
Enderman 2.0
Wither 3.0
Ender Dragon 4.0

F9 — AI Difficulty Scaling

Adjusts the effective TPS threshold based on world difficulty, so optimization triggers earlier on Easy (players care less) and later on Hard (players want full mob behaviour).

Difficulty TPS Offset
Peaceful +3.0 (never optimizes)
Easy −1.0 (optimizes sooner)
Normal 0.0
Hard +1.0 (defers optimization)

F10 — Memory Pressure Penalty

Monitors JVM heap usage ratio. When used heap exceeds the configured threshold (default 80%), a configurable TPS penalty is added, pre-emptively triggering optimizations before a GC pause hits.

F11 — Predictive Scheduler

Tracks historical TPS over a sliding window and a configurable set of peak hours. If a downward TPS trend is detected early (before the threshold is crossed), an earlyOffset penalty is applied to trigger optimizations proactively.

Configurable peak hours example:

peak-hours: "17:00-19:00,19:00-22:00"

F12 — Protected Zones

Mobs inside defined cuboid zones (or WorldGuard regions) are never throttled, culled, or have their attributes modified. Follow range is always restored to default when a mob is found inside a protected zone.

F13 — Smart Group Culling

Instead of culling random mobs, groups entities by type and only targets types with more than min-type-before-cull instances, preserving ecological diversity while reducing the highest-density populations.

F14 — Per-Player Action Bar Notifications

Players near affected mobs receive an action-bar warning during MEDIUM/CRITICAL states. Configurable radius (radius-blocks: 64).

F15 — Alert System

Admin action-bar broadcasts on state transitions. Optional Discord webhook and in-game sound alerts. Sound names, particle types, particle count, and whether to show an action-bar alert are all configurable in monitors.yml under alerts.*. Includes per-player cooldown to prevent sensory spam on multi-world servers.

F16 — Player-Count Scaling

TPS thresholds dynamically tighten as more players join. Configure min-players, max-players, and max-threshold-offset to have the plugin optimize more aggressively during peak player counts.

F17 — Animation Freezing

Freezes the velocity of mobs beyond freeze-distance-chunks during CRITICAL state, preventing physics drift without requiring NMS or packet-level access.

F18 — Config Auto-Backup

Automatically creates timestamped ZIP bundles of all NeuroLag YAML files (including lang/) on a configurable schedule and keeps the N most recent copies. Each backup is accompanied by a .sha256 checksum file that is verified before any restore. Protects against zip-bomb attacks with per-entry (10 MB) and total-restore (50 MB) size caps.

F19 — Safe Mode for Critical State

When enabled in the critical TPS tier configuration, Safe Mode selectively disables only dangerous AI components while preserving essential game mechanics. Prevents over-optimization that would break villager trading, mob escaping water, and other critical behaviors.

F20 — Mob Importance Scoring System

Assigns importance scores to all mobs based on type, naming, tamed status, equipment, and leash status. Named mobs (10x), tamed mobs (20x), and equipped mobs (1.5x) receive higher priority. System protects important mobs during culling operations.

F21 — Mob Behavior Groups

Categorizes mobs into behavior groups for targeted optimization:

  • PASSIVE (low priority): Cows, pigs, sheep, chickens
  • AGGRESSIVE (high priority): Zombies, skeletons, creepers
  • NEUTRAL (medium priority): Endermen, iron golems
  • SPECIAL (preserve): Villagers, bosses, named mobs
  • AQUATIC (water-based): Dolphins, guardians, squids

F22 — Dynamic Region Sizing

Automatically adjusts region size based on player count for optimal performance:

  • 0-5 players: 16 chunks (large regions)
  • 6-20 players: 8 chunks (medium regions)
  • 21-50 players: 4 chunks (small regions)
  • 50+ players: 2 chunks (very small regions)

F23 — Hot Region Decay

Regions gradually cool down when players leave, preventing regions from staying hot indefinitely. Heat decays at 5% per second when no players are present.

F24 — EWMA Prediction Algorithm

Exponentially Weighted Moving Average provides better short-term TPS prediction by giving more weight to recent samples. Alpha smoothing factor of 0.3 for optimal responsiveness.

F25 — Linear Regression Trend Analysis

Detects downward TPS trends using linear regression to predict lag before it occurs. Combines with simple average and EWMA for robust prediction accuracy.

F26 — Annotation-Based Config Validation

@ConfigValidation annotation allows field-level validation rules for configuration values. Validates numeric ranges, required fields, and boundary warnings with clear error messages.

F27 — Config Migration System

Automatic version checking and stepwise migrations for config files. Creates backups before migration and supports rollback. Migrates config.yml, features.yml, monitors.yml, and systems.yml while preserving user settings.

F28 — Event-Driven Architecture

EventBus pattern decouples optimization logic from the main engine. Components can register as OptimizationListener to react to optimization state changes, enabling plugins/addons to extend functionality.

F29 — Refactored Optimizer Classes

Optimization logic extracted into dedicated classes following Single Responsibility Principle:

  • MobCuller - Entity culling with importance scoring
  • AIThrottler - AI throttling and tick management
  • SpawnSuppressor - Spawn rate adjustment logic

F30 — Comprehensive Config Guide

CONFIG-GUIDE.md provides detailed explanations for all configuration options, including usage examples, recommended values, and troubleshooting tips organized by functional areas.

F31 — Enhanced Config Comments

All YAML configuration files (config.yml, features.yml, monitors.yml, systems.yml) include detailed inline comments, section headers, and security notes for better understanding and configuration management.


📊 Monitoring & Reporting

Feature Description
BossBar Dashboard Real-time TPS, state, CPU, and heap display for admins
Web Dashboard Embedded HTTP server at configurable port with JSON API
ASCII Graph /nlag graph — TPS history chart in chat
HTML Audit Reports On-demand or auto-generated reports covering server specs, plugin list, chunk stats, and mob analysis. Entity collection is capped at 5 000 per world to avoid main-thread spikes. Full HTML escaping prevents XSS.
Lag Reports Logged when critical events last more than the minimum duration
Metrics API Plugin-message channel (neurolag.api) for third-party integrations

🔗 Multi-Server Sync

Propagates TPS state across a network in real time. Supports:

  • Redis (recommended) — sub-100 ms latency via Pub/Sub
  • MySQL — polling-based, works with any shared database

Cascade warnings alert local admins when a peer server enters CRITICAL state.


🗂️ Config Profiles

Switch between named configuration presets at runtime:

/nlag profile survival
/nlag profile event
/nlag profile clear

Profiles override critical-tps, medium-tps, and max-entities without touching your base config files.


🧩 Developer API

NeuroLagAPI api = NeuroLagAPI.getInstance();

api.getCurrentTps();
api.getWorldState("world");           // "NORMAL" | "MEDIUM" | "CRITICAL"
api.isManualOverride();
api.getCriticalActivationCount();
api.getMediumActivationCount();

🔁 How It Works

Every check-interval seconds (default: 10):

  Raw TPS
    │
    ├─ Memory pressure penalty  (if heap > threshold)
    ├─ CPU throttle penalty     (if CPU > threshold)
    ├─ Predictive offset        (if downward trend detected)
    └─ Difficulty scaling       (per-world adjustment)
            │
            ▼
       Effective TPS
            │
   ┌────────┴─────────┐
   │  Hysteresis FSM  │   NORMAL ↔ MEDIUM ↔ CRITICAL
   └────────┬─────────┘
            │
   ┌────────┴────────────────────────────────┐
   │  Per-world optimization pass            │
   │  • Collect targets (cached 4 ticks)     │
   │  • Spawn suppression                    │
   │  • Smart culling (if CRITICAL)          │
   │  • Batched AI/range update (≤ 50/batch) │
   │  • Admin + player notifications         │
   └─────────────────────────────────────────┘

On recovery to NORMAL:
  → restoreWorld() — full AI + default FOLLOW_RANGE for all mobs

📦 Requirements

Component Version Notes
Java 21+ Required
Paper 1.21+ Required; Spigot is not supported
WorldGuard 7.x Optional — enables WG region integration
Redis Any recent Optional — for multi-server sync
MySQL 8.x Optional — alternative sync backend

🚀 Installation

  1. Download NeuroLag-1.5.2.jar from Modrinth.

  2. Place it in your plugins/ folder.

  3. Start the server once to generate all config files.

  4. Edit the files in plugins/NeuroLag/:

    File Purpose
    config.yml TPS thresholds, target rules, per-world overrides
    features.yml Toggle and tune each optimization feature
    monitors.yml Dashboard, web API, alerts, Discord, audit
    systems.yml Sync, zones, profiles, backup, validator
  5. Run /nlag validate to catch configuration errors.

  6. Run /nlag status to confirm everything is active.

⚠️ Do not use /reload. Always do a full server restart or use /nlag reload for NeuroLag-specific changes.


⌨️ Commands

Command Description Permission
/nlag status TPS, CPU, heap, per-world states, activation counts neurolag.admin
/nlag graph ASCII TPS history chart (last 60 samples) neurolag.admin
/nlag toggle Pause / resume monitoring and mob optimizations neurolag.admin
/nlag simulate <tps|clear> Force a TPS value for testing (0–20) neurolag.admin
/nlag dashboard [off] Show / hide BossBar dashboard neurolag.dashboard
/nlag audit Generate an HTML audit report neurolag.audit
/nlag zone Show loaded protected zones neurolag.zone
/nlag profile [name|clear] Switch or clear a config profile neurolag.profile
/nlag validate Validate all config values and report errors neurolag.validate
/nlag backup Create a manual backup ZIP now neurolag.backup
/nlag backup list List available backups neurolag.backup
/nlag backup restore [file] Restore from latest or named backup neurolag.backup
/nlag stresstest [count] [min] Spawn test mobs for load testing neurolag.stresstest
/nlag sync Show multi-server peer TPS states neurolag.admin
/nlag reload Hot-reload all NeuroLag config files neurolag.admin

Aliases: /neurolag, /nl, /neuromob


🔐 Permissions

Permission Description Default
neurolag.admin Full control; grants all sub-commands OP
neurolag.dashboard Use /nlag dashboard OP
neurolag.audit Use /nlag audit OP
neurolag.zone Use /nlag zone OP
neurolag.profile Use /nlag profile OP
neurolag.validate Use /nlag validate OP
neurolag.backup Use /nlag backup OP
neurolag.stresstest Use /nlag stresstest OP
neurolag.web Web dashboard access control (outside Bukkit) OP
neurolag.api Read plugin metrics via NeuroLagAPI true

🔧 Configuration

NeuroLag uses a split-config layout. All files are in plugins/NeuroLag/.

config.yml — Core Settings

settings:
  language: en                # en, vi, es, fr, de, ja, zh
  check-interval: 10          # seconds between TPS samples
  enable-logging: true
  hysteresis-buffer: 0.5      # TPS gap before state recovers

tiers:
  medium:
    tps-trigger: 18.0
    range-multiplier: 0.5     # scale mob FOLLOW_RANGE to 50% in MEDIUM
  critical:
    tps-trigger: 15.0

targets:
  hostile-mobs: true
  passive-mobs: false
  water-mobs: true
  whitelist-types: [WARDEN, ELDER_GUARDIAN, ENDER_DRAGON, WITHER]
  protect-named-mobs: true
  protect-tamed-mobs: true

features.yml — Optimization Toggles

culling:
  enabled: true
  max-entities-per-world: 500
  priority: "FAR_FROM_PLAYER"   # FAR_FROM_PLAYER | GROUP | RANDOM

chunk-ai:
  enabled: true
  distance-chunks: 4

tick-throttle:
  enabled: true
  ticks-per-ai-tick: 4

spawn-suppression:
  enabled: true
  monster-limit: 30
  animal-limit: 10

cpu-throttling:
  enabled: true
  cpu-threshold: 80
  mode: THROTTLE_TASKS

memory-pressure:
  enabled: true
  percent: 0.80               # 80% heap used = apply penalty
  offset: 0.5

smart-culling:
  enabled: true
  cull-in-groups: true
  min-type-before-cull: 2
  removal-particle: POOF

monitors.yml — Dashboard & Alerts

dashboard:
  enabled: true
  type: BOSSBAR
  update-interval: 2
  bossbar:
    name: "Server Health"
    color: BLUE

web-dashboard:
  enabled: true
  port: 8080
  auth:
    token: "change-this-token-now"
    require-auth: true
    allow-query-token: false    # keep false for security

discord:
  enabled: false
  webhook-url: ""
  notify-on-critical: true
  notify-on-recovery: true

audit-reports:
  enabled: true
  generate-on: CRITICAL_EVENT
  output-format: HTML

systems.yml — Maintenance & Sync

stress-test:
  enabled: false
  max-mob-count: 2000
  cooldown-seconds: 300
  max-mobs-per-chunk: 80          # NEW 1.5.2 — crash-prevention density cap
  entity-types:
    - ZOMBIE
    - SKELETON
    - CREEPER

multi-server:
  enabled: false
  backend: REDIS              # REDIS or MYSQL

zone-protection:
  enabled: false
  integrate-worldguard: false
  zones:
    - "world 0 60 0 100 200 100"

config-profiles:
  enabled: true
  profiles:
    survival:
      critical-tps: 15.0
      medium-tps: 18.0
      max-entities: 500

auto-backup:
  enabled: true
  backup-interval-minutes: 60
  keep-backups: 10

🔒 Security (v1.5.2)

NeuroLag 1.5.2 ships with three security improvements to the web dashboard:

Feature Default Config Key
Auto-generated secure token Enabled (replaces placeholder on every start() call, even when dashboard is disabled) web-dashboard.auth.token in monitors.yml
Per-IP rate limiting 60 req/min web-dashboard.rate-limit in monitors.yml
IP allow-list Disabled web-dashboard.ip-whitelist in monitors.yml

On first startup, if the token is still "change-this-token-now", NeuroLag automatically generates a cryptographically secure random token, saves it to monitors.yml (creating the file if needed), and prints it to the console. Use it as your Authorization: Bearer <token> header.

1.5.2 fix: Token generation now runs before the enabled check, so the placeholder is replaced even if you have web-dashboard.enabled: false. Previously, flipping the dashboard on after initial setup could expose the default token until the next restart.


🌐 Web Dashboard

The embedded HTTP server exposes a live dashboard and JSON API.

Routes:

Route Method Description
/ GET HTML live dashboard (auto-refreshes)
/api/status GET JSON metrics snapshot
/api/cmd POST Limited command bridge

Allowed commands via /api/cmd: reload, status, graph, validate

Authentication:

Always use the Authorization: Bearer <token> request header. The ?token=... query-string fallback is disabled by default (allow-query-token: false) because tokens in URLs appear in server access logs and browser history.

# Correct
curl -H "Authorization: Bearer my-secret-token" http://localhost:8080/api/status

# Works but insecure — only if allow-query-token: true
curl "http://localhost:8080/api/status?token=my-secret-token"

⚠️ Always change the default token and never expose the web dashboard port publicly without a reverse proxy or firewall rule.


🔗 Multi-Server Sync

Share TPS state across a network so operators can see the health of every node from one place.

Redis (recommended)

multi-server:
  enabled: true
  backend: REDIS
  cascade-warnings: true
  redis:
    host: localhost
    port: 6379
    password: ""

MySQL

multi-server:
  enabled: true
  backend: MYSQL
  mysql:
    host: localhost
    port: 3306
    database: neurolag
    user: root
    password: ""

Use /nlag sync to see live peer states:

[NeuroLag] This server: MyServer_25565
  - LobbyServer_25565  →  19.8 TPS  [NORMAL]
  - SurvivalNode_25566 →  16.2 TPS  [MEDIUM]

v1.5.1: Redis subscriber now exits cleanly on reload. MySQL reconnect uses exponential back-off to avoid log spam during DB outages.


🛡️ Protected Zones

Define cuboid zones where mobs are never optimized, throttled, or culled.

zone-protection:
  enabled: true
  integrate-worldguard: false   # set true to also protect WorldGuard regions
  zones:
    - "world 0 60 0 100 200 100"       # world minX minY minZ maxX maxY maxZ
    - "world_nether -50 0 -50 50 128 50"

Protected mobs always have:

  • AI enabled
  • FOLLOW_RANGE restored to Minecraft default
  • Velocity unfrozen
  • Immunity from smart culling

v1.5.1: FOLLOW_RANGE is now unconditionally restored for protected mobs on every optimization pass, not just when the mob happens to re-enter the zone.


🗂️ Config Profiles

Switch between named presets at runtime without editing files.

config-profiles:
  enabled: true
  profiles:
    survival:
      critical-tps: 15.0
      medium-tps: 18.0
      max-entities: 500
    event:
      critical-tps: 14.0
      medium-tps: 17.0
      max-entities: 900
    minigame:
      critical-tps: 12.0
      medium-tps: 16.0
      max-entities: 1000
/nlag profile event     — switch to event profile
/nlag profile clear     — return to base config
/nlag profile           — show all profiles + current active

💾 Backup System

Automatic backups save all NeuroLag .yml files (including lang/) as timestamped ZIP bundles.

auto-backup:
  enabled: true
  backup-interval-minutes: 60
  keep-backups: 10

Backups are stored in plugins/NeuroLag/backups/.

/nlag backup                                          — create now
/nlag backup list                                     — list all
/nlag backup restore                                  — restore latest
/nlag backup restore config-bundle-2026-04-18_12-00-00.zip

v1.6.0 security improvements:

  • Each backup ZIP is accompanied by a .sha256 checksum file.
  • Restore verifies the checksum before extracting; a mismatch aborts with a SEVERE log.
  • Zip-bomb protection: 10 MB per-entry cap and 50 MB total-restore cap.
  • Backup list is cached in memory; purgeOld() uses filename-based sort — no filesystem stat calls.

v1.5.1: The lang/ subdirectory is included in all backup bundles so custom language files are not lost on restore.


🧩 Developer API

// Get the API instance
NeuroLagAPI api = NeuroLagAPI.getInstance();

// Read current TPS and world state
double tps       = api.getCurrentTps();
String state     = api.getWorldState("world");     // "NORMAL" | "MEDIUM" | "CRITICAL"
boolean override = api.isManualOverride();

// Read lifetime counters
int critCount    = api.getCriticalActivationCount();
int medCount     = api.getMediumActivationCount();

Subscribe to state changes via the plugin-message channel neurolag.api (requires neurolag.api permission set to true on the target player).


🔍 Troubleshooting

Stress test crashes the server when spawning many mobs at spawn

Fixed in 1.5.2. The stress test now checks per-chunk mob density (7×7 chunk grid around the spawn point) against stress-test.max-mobs-per-chunk (default 80) before spawning. If the limit would be exceeded, the count is reduced automatically. Update to 1.5.2.

Web dashboard token was still the default placeholder after enabling the dashboard

Fixed in 1.5.2. Token generation now runs before the enabled check, so the placeholder is always replaced regardless of whether the dashboard starts or not. Update to 1.5.2.

MySQL log spam: "connection lost — reconnecting" floods console during DB outage

Fixed in 1.5.2. Reconnect log messages are now suppressed using the same power-of-2 streak filter used for SQL errors (logs on streak 1, 2, 4, 8, 16 …). Update to 1.5.2.

Entity count stays above maxEntities permanently when zone protection is active

Fixed in 1.5.2. The culling pass now pre-filters protected mobs before calculating the removal count, so the math is correct and the engine converges to the target entity count even when a subset of mobs is zone-protected. Update to 1.5.2.

Mobs are frozen after /nlag toggle or /nlag reload

Fixed in 1.5.1. In-flight batch tasks were re-applying AI restrictions after restoreAll() ran. Update to 1.5.1 and the issue is resolved. If you are running 1.4.0, trigger a full server restart as a workaround.

TPS keeps spiking on a mob-heavy server even with NeuroLag active

Make sure collectTargets caching is active (1.5.1+). On older versions, the entity scan ran every tick. Also lower check-interval and reduce max-entities-per-world in features.yml.

FOLLOW_RANGE stays reduced after server recovers to NORMAL

Fixed in 1.5.1. Protected-zone mobs and mobs in worlds returning to NORMAL now always have FOLLOW_RANGE reset to the Minecraft default via the new restoreWorld() call.

Redis/MySQL exceptions flooding the log on reload

Fixed in 1.5.1. Redis subscriber now joins before pool close. MySQL reconnect uses exponential back-off so errors only log at streaks 1, 2, 4, 8, 16, …

Web dashboard token showing in server access logs

Set allow-query-token: false (now the default in 1.5.1) and use the Authorization: Bearer <token> header instead.

Custom language files lost after backup restore

Fixed in 1.5.1. Backup bundles now include the lang/ subdirectory. Restore from a 1.5.1 backup to get language files back.

Mobs inside protected zones being removed by smart culling

Fixed in 1.5.1. The cull() method now checks zoneManager.isProtected() before removing any mob. Update to 1.5.1.

No optimization happening at all
  1. Run /nlag validate — look for config errors.
  2. Run /nlag status — check that Override shows OFF.
  3. Check ignored-worlds in config.yml — your world may be excluded.
  4. Use /nlag simulate 10 to force CRITICAL state and verify mobs respond.
  5. Check targets in config.ymlhostile-mobs and water-mobs must be true.
Web dashboard returns 401 even with the correct token

Ensure you are sending the token in the Authorization header, not the query string (allow-query-token is false by default). Example:

curl -H "Authorization: Bearer your-token-here" http://localhost:8080/api/status
/reload breaks the plugin

Use /nlag reload instead of the server-level /reload command. Server /reload can leave dangling tasks and broken event registrations in any plugin.


❓ FAQ

Does NeuroLag affect player behaviour?

No. It only modifies non-player mob AI and attribute values (FOLLOW_RANGE). Players, their items, and their abilities are never touched.

Will mobs stay frozen permanently?

No. NeuroLag always restores full AI and default attributes when the server returns to NORMAL state, when the plugin is disabled, or when /nlag toggle is used to pause monitoring.

Does it support multiple worlds?

Yes. Each world is tracked independently with its own state machine. Per-world TPS thresholds can be configured in config.yml under world-settings.

Does it support Folia?

No. NeuroLag uses the Bukkit scheduler API which is not compatible with Folia's per-region threading. Folia support is planned for a future release.

Can I use it alongside other optimization plugins?

Yes, but ensure culling and AI-disable settings do not conflict. NeuroLag is designed to coexist with plugins like Spark, ClearLag, and Chunky.

How do I know it's working?

Run /nlag status — you will see current TPS, CPU, heap, per-world states, and lifetime activation counts. Run /nlag simulate 10 to force CRITICAL state and watch mobs respond in real time.

Is the config validator mandatory?

No, but strongly recommended. Run /nlag validate after every manual config edit to catch type mismatches, out-of-range values, and missing fields before they cause runtime errors.

What happens to mobs when I do /nlag reload?

As of 1.5.1: all pending batch tasks are cancelled, restoreAll() runs (mobs get full AI back), then all services restart with the new config. No mobs are left in a restricted state.


📄 Credits

Author: Duong2012G License: Apache 2.0 Modrinth: https://modrinth.com/user/Duong2012G

Open source — contributions welcome.


📋 Changelog

See CHANGELOG.md for a full version history.

Recent highlights:

  • 1.8.0 — Code audit release: 7 bugs fixed, 2 incomplete refactors completed, dead code removed. Key fixes: RegionOptimizer HOT lookup broke after dynamic resize (mobs froze next to players), pendingBatchTasks memory leak on long-running servers, AIThrottler SRP refactor fully wired, applyHotRegionDecay concurrent-modification, EventBus errors logged to System.err
  • 1.7.1 — 5 targeted bug fixes: Safe Mode FOLLOW_RANGE silently overwritten every tick, NullPointerException in SafeModeOptimizer on Slime/Bat entity types, restoreAI() used a hardcoded FOLLOW_RANGE table ignoring custom attributes, HARD/EASY difficulty scaling inverted, Web Dashboard rate-limit map memory leak from scanner IPs
  • 1.7.0 — Major architecture refactor: MobCuller/AIThrottler/SpawnSuppressor SRP extraction, EventBus pattern, MobImportanceScorer, MobBehaviorGroups, dynamic region sizing, EWMA+LR prediction, annotation-based config validation, config migration system
  • 1.5.2 — 5 targeted bug fixes: wrong api-version in plugin.yml, web token not generated when disabled, culling count wrong with protected zones, AI update scheduler saturation, stress test crash on dense spawn areas, MySQL reconnect log spam
  • 1.5.1 — 4 critical + 5 high bug fixes: task leak, mob freeze, entity scan cache, FOLLOW_RANGE restore, query-token security, Redis/MySQL stability, zone culling, lang backup
  • 1.4.0 — Lifecycle overhaul, zone protection, backup bundles, web auth improvements
  • 1.3.0 — Predictive scheduler, zone manager, web dashboard, multi-server sync, config profiles, backup system, developer API

Ченджлог

1.8.0Релиз1.21.9, 1.21.10, 1.21.11 · 2 июня 2026 г.

[1.8.0] — 2026-06-01 — Code Audit: Complete Bug-Fix & Refactor Release

Full-source audit pass following v1.7.1. Every bug identified during the review has been fixed in this release. Two partially-finished refactors from the 1.7.x cycle have been completed, and dead code has been removed.

1.7.1Релиз1.21.9, 1.21.10, 1.21.11 · 20 мая 2026 г.

[1.7.1] — 2026-05-18 — Bug Fix Release

This release corrects five bugs identified in a full source-code audit of 1.7.0. Three of them were silent correctness failures that made advertised features behave differently from their documented intent without producing any visible error.

🔴 Critical Fixes

Fixed — LagEngine — Safe Mode FOLLOW_RANGE silently overwritten every tick

  • Root cause: After SafeModeOptimizer.applySafeMode() set FOLLOW_RANGE = 4.0, the lambda in applyAiBatched() fell through to an unconditional attr.setBaseValue(attr.getDefaultValue() * multiplier) at the bottom of the loop. In CRITICAL state multiplier = 1.0, so the attribute was reset to its default value on every single tick — completely negating the FOLLOW_RANGE reduction that Safe Mode is supposed to maintain.
  • Fix: Added continue immediately after safeModeOptimizer.applySafeMode(mob) to skip the unconditional setBaseValue line, matching the existing pattern used by the pathfinding-distance branch above it.
  • Impact: Safe Mode now actually reduces mob target-scanning range during CRITICAL state as documented. Servers using safe-mode: true will see measurably lower entity processing cost during lag spikes.

Fixed — SafeModeOptimizerNullPointerException crash on certain entity types

  • Root cause: disableExpensiveAI() and the previous restoreAI() called mob.getAttribute(FOLLOW_RANGE).setBaseValue(...) without a null-check. getAttribute() returns null for entity types that do not expose FOLLOW_RANGE (e.g. Slime, Bat, some modded mobs), causing an unhandled NullPointerException that bubbled up through the scheduler and printed a stack trace every tick.
  • Fix: Extracted the result of getAttribute() into a local variable and guarded both call sites with if (attr != null).

Fixed — SafeModeOptimizerrestoreAI() used a hardcoded FOLLOW_RANGE table

  • Root cause: The previous implementation maintained an internal switch table mapping EntityType → double for the restore path. This table was incomplete (missing dozens of types) and ignored any custom attributes set by other plugins or datapacks, silently restoring the wrong range.
  • Fix: Replaced the hardcoded table with attr.getDefaultValue(), which reads the actual server-side default and therefore works correctly for all entity types including custom ones.

🟡 Medium Fixes

Fixed — LagEngineapplyDifficultyScaling() had HARD and EASY inverted

  • Root cause: case HARD → tps + 1.0 raised the effective TPS, causing optimizations to trigger later on Hard worlds. case EASY → tps - 1.0 lowered it, triggering optimizations earlier on Easy worlds. Both are the opposite of what the logic requires: Hard mobs pathfind more aggressively and consume more CPU; optimizations should therefore activate sooner, not later.
  • Fix: Swapped the offsets — EASY → tps + 1.0, HARD → tps - 1.0.
  • Impact: Servers running Hard difficulty worlds will now have mob AI throttled earlier under load, meaningfully reducing the lag window that was previously unaddressed.

Fixed — WebDashboard — Rate-limit map memory leak on long-running servers

  • Root cause: rateLimitCounters and rateLimitWindows only cleared on stop(). Each unique IP that ever touched the dashboard created a permanent entry. On servers with public web dashboards, scanner/probe traffic could accumulate thousands of entries over days of uptime without any mechanism to reclaim the memory.
  • Fix: At the start of each checkRateLimit() call, entries whose 60-second window has already expired are pruned via removeIf, and rateLimitCounters is kept in sync via retainAll. Cost is amortised O(n) across all incoming requests — negligible compared to the HTTP overhead of each call.

🛠️ Code Quality

Documented — LagEngineAIThrottler field is intentionally unused

  • The 1.7.0 refactor extracted AIThrottler as a separate class but did not update the applyAiBatched() call site to delegate to it. The inline throttle logic continued to run using LagEngine's own throttleCounters, leaving AIThrottler as unreachable code with its own duplicate counter map.
  • This release adds an explicit NOTE comment on the field explaining why the field exists, why it is not called, and what is required before delegation can be completed safely. No behaviour change — cleanup is deferred to a dedicated refactor release.

1.7.0Релиз1.21.9, 1.21.10, 1.21.11 · 11 мая 2026 г.

[1.7.0] — 2026-05-01 — Major Architecture & Algorithm Improvements

🚀 Major Features

  • Safe Mode for Critical State

    • Added safe-mode configuration option under critical TPS tier
    • Implemented SafeModeOptimizer to selectively disable dangerous AI components while preserving essential game mechanics
    • Prevents over-optimization that breaks villager trading, mob escaping water, and other critical behaviors
  • LagEngine Refactoring

    • Extracted optimization logic into dedicated classes following Single Responsibility Principle:
      • MobCuller - Entity culling with intelligent importance scoring
      • AIThrottler - AI throttling and tick management
      • SpawnSuppressor - Spawn rate adjustment logic
    • Improved code maintainability and testability
  • Event-Driven Architecture

    • Implemented EventBus pattern for decoupled optimization logic:
      • OptimizationEventBus - Central event dispatcher
      • OptimizationEvent - Event data container
      • OptimizationListener - Interface for event handlers
      • Enables plugins/addons to react to optimization state changes
  • Mob Importance Scoring System

    • Created MobImportanceScorer with comprehensive importance evaluation:
      • Base scores for all entity types (bosses: 1000, villagers: 100, hostile: 10-20, etc.)
      • Dynamic scoring factors: named mobs (10x), tamed mobs (20x), equipment (1.5x)
      • Integration with MobCuller for intelligent culling decisions
  • Mob Behavior Groups

    • Implemented MobBehaviorGroups system for targeted optimization:
      • PASSIVE (low priority): Cows, pigs, sheep, chickens
      • AGGRESSIVE (high priority): Zombies, skeletons, creepers
      • NEUTRAL (medium priority): Endermen, iron golems
      • SPECIAL (preserve): Villagers, bosses, named mobs
      • AQUATIC (water-based): Dolphins, guardians, squids

🧠 Algorithm Improvements

  • RegionOptimizer Enhancements

    • Dynamic Region Sizing: Automatically adjusts region size based on player count
      • 0-5 players: 16 chunks (large regions)
      • 6-20 players: 8 chunks (medium regions)
      • 21-50 players: 4 chunks (small regions)
      • 50+ players: 2 chunks (very small regions)
    • Hot Region Decay: Regions gradually cool down when players leave
      • Heat decays at 5% per second when no players present
      • Prevents regions from staying hot indefinitely
  • PredictiveScheduler Algorithms

    • EWMA (Exponentially Weighted Moving Average): Better short-term TPS prediction
      • Alpha smoothing factor of 0.3 for optimal responsiveness
      • Linear Regression: Trend analysis for TPS decline detection
      • Combines simple average, EWMA, and trend for robust prediction
      • More accurate lag prevention than simple hourly averages

🛠️ Configuration Management

  • Annotation-Based Validation

    • @ConfigValidation annotation for field-level validation rules
    • ConfigValidator class with automatic validation on reload
    • Validates numeric ranges, required fields, and boundary warnings
    • Provides clear error messages and validation reports
  • Config Migration System

    • Automatic version checking and stepwise migrations
    • Backup creation before migration with rollback capability
    • Supports migration of config.yml, features.yml, monitors.yml, systems.yml
    • Preserves user settings while updating structure

📚 Documentation

  • Comprehensive Config Guide

    • CONFIG-GUIDE.md with detailed explanations for all settings
    • Usage examples, recommended values, and troubleshooting tips
    • Clear organization by functional areas
  • Enhanced Config Comments

    • Added detailed explanations to all YAML configuration files
    • Section headers and inline comments for better understanding
    • Security notes and setup instructions where applicable

🔧 Code Quality Improvements

  • Single Responsibility Principle

    • Each class has a single, well-defined responsibility
    • Reduced coupling between components
    • Improved testability and maintainability
  • Modern Java Practices

    • Updated deprecated Bukkit method usage
    • Proper exception handling and logging
    • Thread-safe data structures where appropriate

🎯 Performance Optimizations

  • Intelligent Culling

    • Prioritizes removing low-importance mobs first
    • Preserves named, tamed, and special mobs
    • Reduces impact on gameplay while maintaining server performance
  • Targeted Optimization

    • Behavior-based optimization strategies
    • Different approaches for different mob types
    • More efficient than one-size-fits-all approach

🔄 Backward Compatibility

  • Seamless Migration
    • Automatic config updates preserve existing functionality
    • Graceful handling of missing or corrupt configuration files
    • No breaking changes to existing setups

🐛 Bug Fixes

  • Fixed Memory Leaks

    • Proper cleanup of event listeners and cached data
    • Thread-safe collections with proper synchronization
  • Improved Error Handling

    • Better exception messages and logging
    • Graceful degradation when components fail
    • Validation prevents invalid configurations

1.5.2Релиз1.21.9, 1.21.10, 1.21.11 · 23 апреля 2026 г.

[1.5.2] — 2026-04-23 — Bug Fix & Safety Patch

Fixed — plugin.yml

  • Critical: wrong api-versionapi-version was set to 1.5.1 (the plugin version) instead of the required Bukkit API version 1.21. Paper rejects plugins with a non-standard api-version string, causing the plugin to either fail to load or log a persistent warning on every server start. Changed to api-version: 1.21.

Fixed — WebDashboard

  • Token not generated when monitors.yml is deleted or web dashboard is disabled. ensureStrongToken() was only called after the if (!webDashboardEnabled) return guard, meaning servers that had the dashboard disabled (or whose monitors.yml was deleted and recreated by saveResource) would still have the default placeholder token the first time the dashboard was enabled — a silent security hole.
    • ensureStrongToken() now runs before the enabled check on every start() call.
    • If monitors.yml does not yet exist, saveResource() is called first to create the file structure before the generated token is written into it.

Fixed — LagEngine — Culling count wrong when protected zones are present

  • Protected-zone mobs were counted toward targetRemoveCount but never actually removed, causing the cull pass to under-remove and leaving entity counts above maxEntities indefinitely on servers with active zone protection.
    • cull() now pre-filters protected mobs from the candidate pool before computing targetRemoveCount, so the removal math uses only the actually-cullable mob count.
    • The redundant zone check inside the removal loop is kept as a race-condition safety net.

Fixed — LagEngine — AI update scheduler saturation on very mob-dense worlds

  • No upper bound on runTaskLater calls per tick — on worlds with thousands of entities, applyAiBatched() could schedule dozens of batch tasks in a single tick, queuing more work than the scheduler could drain, leading to compounding latency.
    • Added AI_UPDATE_PER_TICK_CAP = 80: at most 80 mob AI updates are scheduled per engine tick. The next monitor tick processes the remaining mobs, spreading load evenly.

Fixed — StressTestManager — Server crash on large spawns at low-chunk-count locations

  • No per-chunk mob density check — spawning 2 000+ mobs at or near the world spawn could saturate loaded chunks and crash the server within seconds.
    • Before spawning, the manager now scans a 7×7 chunk area around the target location and compares the current entity count against stress-test.max-mobs-per-chunk (default: 80).
    • If the limit would be exceeded, the spawn count is automatically reduced to the safe maximum and a warning is logged. If the area is already at capacity, the command is rejected with a descriptive error message.
  • New config key in systems.yml: stress-test.max-mobs-per-chunk: 80.

Fixed — MultiServerSync — MySQL reconnect attempt logged on every polling cycle

  • When the MySQL database was down for an extended period, ensureConnected() logged "MySQL connection lost — reconnecting in Xs…" on every poll interval (default every 10 s), flooding the console with hundreds of lines.
    • Reconnect log messages are now gated behind the same power-of-2 streak filter already used for SQL error warnings (logs on streak 1, 2, 4, 8, 16 …), reducing noise by up to 95% during prolonged outages while still keeping the first occurrence visible.

Config changes

# systems.yml — new in 1.5.2
stress-test:
  max-mobs-per-chunk: 80   # NEW — per-chunk density safety cap for stress tests

1.5.1Релиз1.5.1 · 20 апреля 2026 г.

[1.5.1] — 2026-04-20 — Code Quality & Performance Patch

Fixed / Improved — ZoneManager

  • WorldGuard region cachegetApplicableRegions() was called for every mob on every monitor tick. Queries are now cached per chunk with a 100-tick TTL (ConcurrentHashMap). Cache is invalidated automatically when TTL expires, eliminating excessive WorldGuard API pressure on large servers.
  • CuboidZone coords changed from double to int — block-level precision is sufficient; int arithmetic is faster and the record is more memory-efficient.
  • Zone initialize() now clears the WG cache on reload.

Fixed / Improved — ProfileManager

  • Profile validation before apply — switching to a profile where critical-tps ≥ medium-tps or max-entities < 1 now returns a clear error instead of silently corrupting the engine state.
  • Active profile persisted across restarts — the selected profile name is written to plugins/NeuroLag/active-profile.dat on switch and reloaded automatically on startup/reload, so profiles survive server restarts without manual re-selection.
  • switchProfile() return type changed from boolean to String (null = success, "NOT_FOUND" or error message = failure) — NeuroLag main command updated accordingly.

Fixed / Improved — PredictiveScheduler

  • Hand-rolled JSON parser replaced with Gson (bundled by Paper) — the previous split / replaceAll parser was fragile and could silently produce wrong data on corrupt files. Gson provides safe serialisation and clean error handling; corrupt files now log a warning instead of producing garbage hourly averages.
  • Loaded samples are capped to the last 60 per hour on load, not only on record.

Fixed / Improved — CpuMonitor

  • Graceful fallback for non-Sun JVMs — if com.sun.management.OperatingSystemMXBean is unavailable (GraalVM, some container JVMs), the monitor now falls back to OperatingSystemMXBean.getSystemLoadAverage() normalised by CPU count. If even that is unavailable, the feature disables itself gracefully instead of throwing at construction time.
  • EMA smoothing (α = 0.3) — single-tick CPU spikes no longer toggle the throttle on/off erratically. The exponential moving average keeps the reading stable under transient load.
  • Strategy (SUN_PROCESS / SYSTEM_LOAD / DISABLED) is selected once at construction and stored in an enum — no repeated instanceof checks every tick.

Fixed / Improved — RegionOptimizer

  • Player chunk position cacherefresh() now tracks each player's last known chunk. The HOT/COLD region map is only rebuilt when at least one player has moved to a different chunk since the previous call. On a stable server this eliminates the full-player-scan every monitor tick.
  • isBeyondPathfindingDistance() uses the cached positions instead of calling world.getPlayers() a second time per mob check.

Fixed / Improved — NeuroLagAPI

  • Added NeuroLagAPI.getInstance() for cleaner third-party plugin integration.
  • JSON payload sent via plugin message channel now uses Gson instead of manual StringBuilder, eliminating potential escape bugs.

Fixed / Improved — LagReporter (Discord)

  • Retry with exponential back-off — Discord webhook requests are retried up to 3 times (delays: 1 s → 2 s → 4 s) before giving up. Transient network errors and Discord 429 rate-limit responses no longer silently drop notifications.
  • Discord embed payload now built with Gson — no more manual string escaping.

Fixed / Improved — StressTestManager

  • Confirmation prompt for spawns > 1 000 mobs — the sender must repeat the command within 30 seconds to confirm. Prevents accidental large spawns.
  • Multiple entity typesstress-test.entity-types config list (default: ZOMBIE, SKELETON, CREEPER) is cycled round-robin across spawned mobs, producing a more realistic mixed load. Invalid or non-spawnable type names log a warning and are skipped.

Fixed / Improved — LagEngine

  • Added internal processing metrics: lastTickMobCount and lastTickProcessingMs. Visible in /nlag status ("Last Tick: N mobs, X ms").
  • ZoneManager.tick() is now called once per engine tick to advance the WG cache TTL counter.

Fixed / Improved — WebDashboard

  • Rate limiting now also covers GET / (the HTML dashboard page), not only /api/* endpoints.
  • Token auto-generation log output upgraded to SEVERE level and formatted as a clearly visible bordered block so admins cannot miss the new token in the console.

Fixed / Improved — ConfigManager / ConfigValidator

  • Added stress-test.entity-types list field.
  • ConfigValidator now checks entity-types list is non-empty when stress test is enabled.

Config changes (systems.yml)

stress-test:
  entity-types:        # NEW — 1.5.1
    - ZOMBIE
    - SKELETON
    - CREEPER

1.5.0Релиз1.21.9, 1.21.10, 1.21.11 · 19 апреля 2026 г.

[1.5.0] — 2026-04-19 — Security Hardening & Stability Release

Fixed — Security

  • [Bug #1] Web dashboard weak default token / no rate limiting / no IP filtering (WebDashboard.java, ConfigManager.java, monitors.yml)
    • Auto-generates a cryptographically strong 24-byte random token on first startup whenever the default placeholder "change-this-token-now" is detected. The new token is immediately persisted to monitors.yml and printed to the console.
    • Added per-IP rate limiting (sliding 60-second window, configurable via web-dashboard.rate-limit.max-requests-per-minute, default 60). Returns HTTP 429 when the limit is exceeded.
    • Added optional IP allow-list (web-dashboard.ip-whitelist, disabled by default). When enabled, only explicitly listed IPs can reach /api/status and /api/cmd.

Fixed — Stability

  • [Bug #2] Stress test could spawn unlimited mobs with no cooldown (StressTestManager.java, ConfigManager.java, systems.yml)

    • Hard cap: mob count is clamped to stress-test.max-mob-count (default 2 000) regardless of the value passed to /nlag stresstest. The sender is notified when the cap applies.
    • Cooldown: a configurable stress-test.cooldown-seconds (default 300) must elapse between tests. Attempting to start a test during cooldown shows the remaining time.
    • Both limits are enforced by ConfigValidator.
  • [Bug #3] Redis subscriber join(3000) always timed out on slow networks (MultiServerSync.java)

    • stop() now holds a volatile reference to the active JedisPubSub instance and calls pubSub.unsubscribe() before interrupt()+join(). This signals the blocking jedis.subscribe() call to return immediately, so join() completes in milliseconds rather than timing out. Prevents connection-pool leaks during rapid /nlag reload cycles.
  • [Bug #4] Smart culling could remove hundreds of entities in one pass → lag spike (LagEngine.java)

    • Added CULL_PER_TICK_CAP = 50 — at most 50 entities are removed per cull invocation. If the entity count remains above max-entities-per-world after one pass, the next monitor tick handles the remainder. Eliminates the single-frame mob-removal lag spike seen on servers with thousands of entities.
  • [Bug #5] Predictive scheduler lost all historical data on server restart (PredictiveScheduler.java)

    • Hourly TPS samples are now saved to plugins/NeuroLag/predictive-data.json on stop() (server shutdown or /nlag reload) and reloaded on start(). No external library required — uses a compact hand-rolled JSON serializer/parser. The predictor now accumulates knowledge across restarts and becomes effective much faster on busy servers.
  • [Bug #6] Full plugin reload caused noticeable server stutter (NeuroLag.java)

    • reloadPluginState() now takes config snapshots before reloading and selectively restarts only the services whose configuration sections actually changed (web dashboard, multi-server sync, predictive scheduler, CPU monitor, boss-bar dashboard). The main monitor task and engine throttle are always restarted cleanly. On a typical /nlag reload that only changes TPS thresholds, zero external services are bounced, eliminating the stutter caused by restarting Redis/MySQL connections unnecessarily.

Changed

  • ConfigValidator now validates the new stress-test limits and rate-limit settings.
  • systems.yml — added stress-test.max-mob-count and stress-test.cooldown-seconds.
  • monitors.yml — added web-dashboard.rate-limit and web-dashboard.ip-whitelist sections.

1.4.1Релиз1.21.9, 1.21.10, 1.21.11 · 18 апреля 2026 г.

[1.4.1] — 2026-04-18 — Bug Fix Release

Fixed — Critical

  • Task leak on reload (/nlag reload)BackupManager.start() was called twice in onEnable() (once directly, once via startRuntimeServices()), causing every scheduled task to be registered a second time on reload. The duplicate direct call has been removed; the initial backup is now triggered asynchronously inside start() when no backups exist. stopRuntimeServices() now also calls engine.cancelAllPendingBatchTasks() before stopping the throttle task, ensuring all in-flight runTaskLater batch tasks are cancelled before any new tasks are registered. (LagEngine, NeuroLag)

  • collectTargets() running every tick on the main threadLagEngine.collectTargets() called world.getLivingEntities() on every monitor tick, causing significant lag spikes on servers with large mob populations. The result is now cached per-world and rebuilt at most once every 4 ticks (~0.2 s). The cache is invalidated on restoreAll() and on world state transitions. (LagEngine)

  • FOLLOW_RANGE not fully restored for protected-zone mobsapplyAiBatched() set AI = true for protected mobs but did not always restore FOLLOW_RANGE to its default value, so mobs could permanently retain a reduced follow range after leaving a zone. The fix unconditionally calls attr.setBaseValue(attr.getDefaultValue()) for every protected mob encountered. Additionally, a new restoreWorld(World) helper is called whenever a world transitions back to NORMAL, guaranteeing a full attribute restore even for mobs that were never re-processed by the batch scheduler. (LagEngine)

  • Manual override (/nlag toggle) not restoring mobs correctly — in-flight runTaskLater batch tasks scheduled by applyAiBatched() could execute after restoreAll() and re-apply AI restrictions or reduced follow ranges, leaving mobs frozen. handleToggle() now calls engine.cancelAllPendingBatchTasks() before engine.restoreAll() so no pending task survives the toggle. (LagEngine, NeuroLag)

Fixed — High

  • WebDashboard query-string token auth — passing ?token=... in the URL is insecure (tokens appear in server access logs, browser history, and HTTP referrer headers). The query-string fallback is now disabled by default. A new config key web-dashboard.auth.allow-query-token (default false) must be explicitly set to true to re-enable it. The existing warning is preserved and now also states the config key needed to disable the fallback permanently. (WebDashboard, ConfigManager, monitors.yml)

  • Redis subscriber thread not shutting down gracefullyMultiServerSync.stop() called redisSubThread.interrupt() but returned immediately, so the thread could still be holding a Jedis resource when jedisPool.close() ran, causing pool-exhaustion exceptions in the server log on every reload. The fix adds redisSubThread.join(3000) after interrupt(), giving the thread up to 3 seconds to exit cleanly before the pool is closed. (MultiServerSync)

  • MySQL reconnect logic throwing repeatedly when DB is downensureConnected() called DriverManager.getConnection() immediately on every sync cycle failure, flooding the log with stack traces. The fix introduces an atomic error-streak counter and an exponential back-off (sleep time = min(streak * 2, 30) seconds before reconnect). Log output now uses a power-of-two gating strategy (log on streak 1, 2, 4, 8, 16, …) to avoid noise during prolonged outages. (MultiServerSync)

  • Batched AI task delay not capped — with 5 000+ mobs the delay between batches could reach 100 ticks (5 seconds), making mobs visibly unresponsive. The delay is now capped at 20 ticks (1 second) regardless of entity count. (LagEngine)

  • Smart culling could remove protected-zone mobs — the culling loop checked zoneManager.isProtected() only in the main optimization path, not inside cull() itself. Mobs inside protected zones can now never be removed by smart culling. (LagEngine)

  • BackupManager not backing up the lang/ directory — the ZIP bundle only included root-level .yml files. Custom language files stored in plugins/NeuroLag/lang/ would be lost on restore. collectConfigFiles() now recursively includes lang/*.yml entries and restoreZip() correctly recreates the lang/ subdirectory on restore. (BackupManager)


1.4.0Релиз1.21.9, 1.21.10, 1.21.11 · 14 апреля 2026 г.

[1.4.0] — Stability + lifecycle fix release

Fixed

  • Removed the command-level permission wall in plugin.yml so feature-specific permissions can actually work.
  • Reworked /nlag toggle so manual override now restores mobs immediately and stops active throttling instead of leaving old optimization state hanging.
  • Reworked /nlag reload to stop and restart runtime services cleanly, including CPU monitor, predictive scheduler, web dashboard, backup scheduler, multi-server sync, and monitor tasks.
  • Multi-server sync now clears stale peers and restarts cleanly on reload.
  • Protected-zone mobs are now excluded from smart culling and have FOLLOW_RANGE restored to defaults when encountered during optimization.
  • Ongoing MEDIUM and CRITICAL states now keep reapplying optimization passes on later monitor ticks, so movement into protected zones / hot zones / player zones is handled more consistently.
  • Stress-test mobs no longer give themselves a custom name, so they are no longer accidentally excluded by the named-mob whitelist.
  • Backup system now stores full zip bundles of NeuroLag YAML files instead of only copying config.yml.
  • Added restore-by-name support for /nlag backup restore <file>.
  • Memory-pressure config now normalizes legacy percentage values above 1.0, and defaults were corrected to ratio format (0.80).
  • Player-scaling ratio is now clamped to avoid negative threshold offsets when online players are below the configured minimum.
  • Predictive scheduler now clears parsed peak-hour ranges on restart/reload to avoid duplicate entries.
  • Zone manager now fully resets cached zone and WorldGuard state when the feature is disabled or reloaded.
  • Web/API JSON generation now escapes keys/values properly and uses stable decimal formatting.
  • Web auth query token parsing is stricter and only logs the fallback warning once.
  • CPU monitor now resets stale displayed values when stopped or disabled.
  • BossBar dashboard now respects dashboard.bossbar.name and dashboard.bossbar.color from monitors.yml.
  • Metrics API plugin-message registration now reads the correct split config source.

Docs

  • Updated README to reflect the real split-config layout.
  • Updated README examples for web-dashboard, multi-server, zone-protection, config-profiles, and backup restore.
  • Updated language file version headers to v1.4.0.

Комментарии

Загружаем…