Project SkyFire · GPL 3.0 · Copyright and attribution
Optional, report-only movement monitoring for Project SkyFire 5.4.8. Requires
SkyFire_548 main commit 79bd1b3fdf or later with the movement module hooks.
This is the initial standalone implementation, not a complete port of PR #1191.
From your core source directory:
git clone https://github.com/ProjectSkyFire-Modules/anticheat.git modules/mod-anticheatReconfigure CMake with MODULES=ON and MOD_ANTICHEAT=ON, build worldserver,
then run INSTALL. Use the exact folder name mod-anticheat for loader discovery.
Copy the installed anticheat.conf.dist to anticheat.conf beside the actual
worldserver.conf supplied to worldserver. Restart worldserver or use the core's
configuration reload command. Missing config disables monitoring.
Anticheat.ConfVersion is checked by the module at startup and on configuration
reload. It is independent of worldserver's ConfVersion; the module never sets
or changes the core serial. .anticheat status displays installed and expected
module serials.
A missing, invalid or older serial produces an update warning. A newer serial
warns that the module binary and config may not match. Like the core's version
check, these warnings do not stop startup, disable monitoring or rewrite files.
Merge changes from anticheat.conf.dist, preserve your settings, then update the
serial and reload. Merely changing the serial does not update a configuration.
Module maintainers must bump the YYYYMMDDNN serial in src/ModuleConfig.h and
conf/anticheat.conf.dist together when changing the configuration template.
The default log-only mode needs no SQL updates. Optional database history requires the module schema described below. Removing the module and reconfiguring the core removes the feature; retained reports remain available in the character database.
- Horizontal speed monitoring uses a bounded distance budget, server monotonic time and server speed values. Client timestamps and jump speed are not trusted.
- A grace period resets measurements around login, map changes, teleports, server speed changes, splines and knockback impulses.
- Transports, vehicles, taxis, active splines and high-latency sessions are
excluded. Staff accounts are excluded unless
Anticheat.CheckStaff=1. - Optional fly and water-walking flags are compared with aura authorization. These experimental checks default off: script-granted abilities without a corresponding aura may trigger reports.
- Optional client-clock acceleration monitoring compares elapsed client time
against a server monotonic-time window. It tolerates 32-bit timestamp wrap and
batching, and resets on long gaps, backward timestamps and movement exemptions.
Enable
Anticheat.ClientClock=1to test it. It defaults off pending live testing; it never increases the allowed movement budget or rejects a packet. - Optional teleport reports flag horizontal displacement exceeding both a minimum distance and a server-speed/time envelope. Legitimate server teleports reset the baseline through the core hook. This does not detect vertical-only warps.
- Optional repeated-jump reports require a second rising jump and a server terrain sample showing the player off the ground. Verified landing resets the jump sequence; client landing/falling flags alone do not prove ground contact.
- Optional climb reports look for steep, rapid grounded ascent over at least
500 ms. Flying, swimming and server-authorized movement exemptions apply.
Missing terrain is not evidence. Terrain queries run outside the module mutex,
at most once per
Anticheat.TerrainIntervalMsper eligible player (default 250ms), and are absent when jump/climb checks are disabled. All three new checks default off; calibrate them on your server before relying on the reports. - Reports are rate-limited independently per player and detector. Counts are per login session and saturate rather than overflowing. Logout clears them; configuration reload resets movement baselines while retaining counts.
- Log messages use category
anticheatat WARN level. Configure a dedicated core log appender if desired; the core's logger configuration controls output. - Speed logs include distance, remaining distance allowance, elapsed server time
and latency. Clock logs include client/server elapsed time and latency. These
details accompany the summary log. With the evidence SQL migration installed,
measurements and thresholds are also saved with each report and displayed by
.anticheat history. Older schemas continue saving basic reports with a warning. - Administrators can opt into live chat alerts for their current login session. Delivery runs on the world thread and rechecks administrator security and RBAC. A shared queue holds at most 100 alerts, drops the oldest on overflow, expires entries after ten seconds and delivers at most five per second per subscriber. These limits affect chat only, not the existing report log/database path.
No packet rejection, teleport correction, jail, kick or ban is performed. A report is evidence to investigate, not proof of cheating. Speed checks use a conservative ceiling and do not detect every movement exploit: brief bursts within slack, vertical-only displacement, backward/reset clock manipulation, collision bypass, manipulated transport membership, controlled creatures, battleground boundaries, and movement during exemption windows need further work. Server flight capability currently raises the speed ceiling; it is not a separate authorization validator.
Commands require administrator security and the existing server info RBAC
permission. Console can run status, history and top; player/clear require a session.
| Command | Result |
|---|---|
.anticheat status |
Enabled state, enabled detectors and tracked player count |
.anticheat player |
Reports for the selected online player, or yourself |
.anticheat clear |
Clear that player's session reports and reset its baseline; preserve database history |
.anticheat history <GUID> |
Latest 10 persisted reports for a character's numeric low GUID, including offline characters |
.anticheat top |
Top ten current-session report totals, with per-detector counts; available in console |
.anticheat alerts on|off |
Subscribe/unsubscribe to administrator chat alerts for this login session |
Anticheat.Alerts=1 allows subscriptions but does not automatically subscribe
anyone. Logout removes the subscription. Set it to 0 to stop alert delivery
globally. Configuration reload clears queued alerts; subscriptions remain for
the current session and resume if monitoring and alerts are re-enabled.
- Import
sql/pending_updates/characters/create_anticheat_reports.sqlinto the character database, thenextend_anticheat_report_evidence.sqlfrom the same directory. Both files are idempotent and preserve existing reports. The second file adds the evidence column for existing installations; new installations already have it. Module SQL is not automatically imported by the core updater. - Set
Anticheat.DatabaseReports=1inanticheat.confand reload configuration. - Confirm
.anticheat statusshowsDatabase=1. Missing columns or an unavailable schema disable persistence and produce a startup/reload error; log-only monitoring remains available.Detailed database evidence=1confirms the optional evidence column passed its config-time check. Apply the migration and reload if detailed evidence is unavailable.
The module queues one INSERT per cooldown-qualified report using the core's asynchronous database worker. The movement callback does not wait for SQL. Each row records the event's UTC Unix timestamp, character/account IDs, map, detector, opcode, position (integer thousandths of a yard), latency and, when supported, up to 512 bytes of module-generated numeric evidence. It contains no IP, chat text or credentials. Detector IDs are stable: 0=speed, 1=fly, 2=waterwalk, 3=client-clock, 4=teleport, 5=jump, 6=climb. Existing IDs are unchanged. Rows created before the evidence migration remain readable with an empty evidence field. Evidence uses a bounded hex SQL literal so map threads do not access a shared MySQL connection to escape strings; report INSERTs remain asynchronous.
History survives relog and worldserver restart, but pending asynchronous writes
can be lost in a crash or database outage. Check the core SQL log for write
failures. Database=1 means the schema passed the last config-time check; it is
not a live database health probe. History queries are explicit administrator
operations and return at most ten rows, using the character/history index.
No automatic retention or deletion is enabled. Operators should set a retention
policy appropriate to their server and maintain the module table separately.
Disable persistence before removing its table. Reimporting the initial SQL never
deletes rows, and .anticheat clear does not delete stored evidence.
Independent detector tests (no database or core build required):
cmake -S tests -B tests/build
cmake --build tests/build --config Release
ctest --test-dir tests/build -C Release --output-on-failureTests cover normal running, sustained excessive speed, batching, zero elapsed time, resets, stalls, clock regression, invalid samples and bounded idle credit. Additional cases cover client-clock acceleration, timestamp wraparound, batching, report argument boundaries and configuration serial compatibility. Alert tests cover capacity, burst limits, expiration, clearing and clock regression; evidence tests verify values from the actual detector sample. Traversal tests cover valid running/stairs, displacement, repeated airborne jumps, verified landing, forced-movement resets, grounded climb, missing terrain, stalls, and invalid samples. SQL tests can validate fresh installs and repeatable upgrades in an automatically created and removed scratch database:
python tests/test_report_schema.py --mysql mysql --host 127.0.0.1 --user rootProvide a password through the MYSQL_PWD environment variable if necessary.
The test account needs permission to create/drop a scratch database. This test
does not select or alter the live character database.
They do not validate the worldserver adapter or packet behavior; build the module
with the core and follow the live test checklist.
Inspired by the feature proposal in SkyFire PR #1191 by acidmanifesto (M'Dic). The standalone implementation replaces its embedded manager, calculations and punitive actions rather than copying them into the core. Licensed under GPL v3; see LICENSE.md and COPYRIGHT.md.
