LumoAiDetector icon

LumoAiDetector -----

An experimental anti-cheat that trains a local Random Forest model on your server's combat data




0.1.2
This release is mostly about honesty and stability: training you can reproduce, metrics that do not lie, and concurrency that does not lose your data.
Training
  • Reproducible runs. Set training.seed to a fixed, non-zero value and the same dataset and settings produce the same model. Leave it at 0 for a fresh random seed each time.
  • Class balancing. New training.balance-classes and training.class-weight-cap weight the minority class up, so a small cheater or legit sample is not drowned out by the majority.
  • Honest metrics. When there is no validation holdout, the training message and the model metadata now say the numbers came from training data. No more treating a training-set score as an independent estimate.
Commands
  • Added /lad models compare <a> <b> to put two models side by side.
  • /lad models info now shows the metrics source, whether classes were balanced, and the training seed.
  • /lad status and /lad dataset info read the dataset off the main thread.
Performance
  • Predictions run on their own thread pool (performance.prediction-threads), separate from the dataset writer, so heavy inference does not block recording.
  • Dataset counting and trimming stream the file line by line instead of loading every row into memory.
  • Optional ping band (detector.min-ping-ms, detector.max-ping-ms) skips windows recorded under unusual latency.
Fixes and hardening
  • Alert history is now read and written under proper synchronization.
  • Shutdown stops predictions, drains queued writes, then closes the writer in the right order, so recorded windows are not lost.
  • Model files load through an allow-list deserializer that only resolves model and core JDK classes.
  • Added a JUnit test suite for metrics, GCD math, prediction tracking, dataset parsing, and path handling.
Test on a local server before production, and keep backups of your models and datasets.
----------, Jun 10, 2026

What changed

Alert history no longer sits in memory forever. When a player left, their state was cleaned up but the alert history stayed. On a server with a few thousand unique players over a week, that turned into a slow leak. Fixed now.
The IO executor waits for pending writes before shutdown. It was sending a shutdown signal and walking away. If the dataset had queued rows, they got lost. Now it waits up to ten seconds. If the writes do not finish in time, it logs a warning and moves on.
pruneStatesIfNeeded stopped hammering every tick. It ran on every single PlayerMoveEvent, checking the state map size and calling Bukkit.getPlayer for every UUID. That is pointless work. Now it runs at most once every five seconds.
Windows path traversal in dataset-path is blocked. A config value like C:\evil\file passed the existing check because it does not contain .. or start with /. Now drive-letter paths are rejected too.
Model metadata is written once, not twice. saveModel wrote the metadata file, read it back, added the SHA-256, and wrote it again. Now SHA-256 is computed before the first write and included from the start.
CSV formatting is faster. String.format with Locale.US on every feature value adds up across thousands of windows. Replaced with a ThreadLocal DecimalFormat. About three times faster.
Model training adapts to your data now. Small datasets get conservative trees with limited depth to avoid overfitting. Large datasets get deeper trees for better accuracy. The train/validation split is stratified, so class ratios are preserved. If one class heavily outnumbers the other, the model adds regularization to cut down false positives.
New features
  • /lad dataset trim <rows> - keep only the last N rows and delete the rest
  • LumoAiDetector.bypass permission - exempt a player from detection entirely
  • detector.disabled-worlds in config.yml - disable detection in specific worlds
  • detector.whitelisted-uuids in config.yml - exempt players by UUID without a permission plugin
  • punishment.notify-player in config.yml - send a warning to the player when punishment triggers
  • {world} and {ping} placeholders for punishment commands
  • performance.async-prediction in config.yml - run ML predictions off the main thread
Bug fixes
  • Fixed alert history not being cleaned up when a player disconnects.
  • Fixed hardcoded English text in /lad dataset info (now reads from messages.yml).
  • Fixed IO executor not waiting for pending writes on server shutdown.
  • Fixed pruneStatesIfNeeded running on every PlayerMoveEvent.
  • Fixed Windows drive-letter paths passing the dataset-path security check.
  • Fixed saveModel writing metadata file twice instead of once.
  • Fixed String.format being called 120 times per recorded window in CSV writing.
  • Fixed target() checking every entity in the bounding box without an early distance filter.
What you do to upgrade
1. Replace the jar.
2. Start the server.
3. That is it.
The config and dataset from 0.1.0 are backward compatible. New config keys have safe defaults.
----------, Jun 2, 2026

Changelog

What changed
Threading is no longer aspirational. The old code had ScheduledFuture fields with no visibility guarantees, shared DecimalFormat instances, a BufferedWriter that got replaced mid-write, and computeIfAbsent called from concurrent paths without a ConcurrentMap. Every one of those caused data corruption or silent drops under load. All of them are fixed.
Model training no longer blocks your entire server. It now runs on a dedicated trainExecutor thread pool. You can train a fifty-tree model on fifty thousand rows without timing out the main thread.
Recording stops when the server stops. Not after. There is a proper shutdown hook now. Your last session will not be truncated.
Dates are UTC everywhere. Not JVM default, not Moscow time, not whatever the hosting provider configured. UTC.
New features
[*] /lad models info <name> - see accuracy, precision, recall, and F1-score for any model
[*] /lad dataset info - row counts by class, file size, skipped rows
[*] /lad check history <player> - replay recent check results for a player
[*] /lad record stop all - stop every active recording session at once
[*] Command aliases - active works like modelactivate, deactivate like modeldeactive, delete like modeldeleted. Old names still work.
[*] max-dataset-rows in config.yml - cap the dataset size before it eats your disk
[*] Build scripts - build.ps1 for Windows, build.sh for Linux
Bug fixes
[*] Fixed Location.subtract() mutating the entity's actual position in the world. The detector was not just reading location data, it was moving the player.
[*] Fixed SimpleDateFormat breaking under concurrent access from multiple threads.
[*] Fixed ScheduledFuture field visibility across threads. The cancel method was sometimes running on a null handle.
[*] Fixed DecimalFormat instance shared across threads without synchronization.
[*] Fixed BufferedWriter being replaced mid-recording, losing buffered data.
[*] Fixed catch(Throwable) masking OutOfMemoryError and other serious JVM problems.
[*] Fixed reader and serializer streams not closing when constructors threw.
[*] Fixed PluginSettings field not visible across threads on reload.
[*] Fixed GCD calculation producing negative values for large tick differences.
[*] Fixed dataset row limit not being enforced during recording.
[*] Fixed label change warning message being untranslated.
[*] Fixed RuntimeStateService returning stale cached state after state transitions.
[*] Fixed /lad models info with no argument causing a StackOverflowError from infinite recursion.
[*] Fixed recordings not stopping cleanly when the server shuts down.
Security
[*] SHA-256 hash verification for all downloaded model files
[*] Path traversal prevention - model names containing .. or / are rejected
[*] Model name length limited to 64 characters to prevent filesystem abuse
What you do to upgrade
[*] Replace the jar
[*] Start the server
[*] That is it
The config file and dataset are backward-compatible. If you use the old command names in scripts or chat binds, they still work - the aliases are transparent.
License
Apache License 2.0. Do not remove my name or reupload as your own. If you fork it, use a different name and mention the original. Full terms in the LICENSE file.
----------, Jun 1, 2026

Resource Information
Author:
----------
Total Downloads: 19
First Release: Jun 1, 2026
Last Update: Jun 10, 2026
Category: ---------------
All-Time Rating:
2 ratings
Find more info at github.com...
Version -----
Released: --------------------
Downloads: ------
Version Rating:
----------------------
-- ratings