HardAntiCheat
Anti-cheat plugin for Atlyss multiplayer. (In Public Testing)HardAntiCheat
A powerful, configurable, server-side anti-cheat engine for Atlyss.
Join the Discord Community
This mod is a server-authoritative anti-cheat designed to block common exploits by making the server the source of truth for player actions. It is highly configurable, allowing hosts to tailor the detections to their server's specific mods and balance.
All detected infractions are logged with player details in the BepInEx\plugins\HardAntiCheat\HardAntiCheat_InfractionLog.txt file for server admin review.
⚡ New in v2.0+: Thunderstore auto-whitelisting, human-readable kick messages, vanilla client support, live settings reload, and server-wide broadcast announcements!
✨ Key Features
- 🔐 Server-Authoritative Verification: All checks run on the server; clients cannot bypass them.
- 🧩 Mod List Verification: Via CodeTalker, verifies client-loaded mods against blacklists/whitelists/Thunderstore.
- 🌩️ Thunderstore Integration: Auto-whitelists all mods published on Thunderstore; blocks deprecated/flagged mods.
- 👤 Human-Readable Logs: Kick messages show
ModName (GUID) vVersionfor easy blacklisting/whitelisting. - 🎮 Vanilla Client Support: Players without mods can join seamlessly; only modded clients are verified.
- ⚙️ Live Settings Reload: Change configs in-game via EasySettings—no restart required.
- 📢 Server Broadcasts: Kick/ban announcements appear in cyan chat for all players via
[HAC]prefix. - 🚀 Background Verification: Unknown mods are verified asynchronously after player joins—no handshake timeouts.
- 🔤 Case-Insensitive Matching: GUID lists work regardless of capitalization in config.
- 🛡️ Comprehensive Detections: Movement, XP, cooldowns, spam, revive, teleport, fly, and more.
- 🔗 Connection Limit: Caps simultaneous connections per Steam ID on the server, stopping multi-client "cloner" mods. The limit is enforced at the Steam transport before the game ever sees an extra connection, with a periodic scan as a second layer. Host-only; clients do not need HAC.
- 📊 Attribute Budget: Flags players whose attribute points (unspent plus spent) exceed what their level allows, however they got them. Optional respec with full refund.
- 🎓 Skill Point Budget: Flags players whose unlocked skills cost more skill points than their level has ever handed out. Optional reset with full refund, carried out by the player's client.
Instructions
- Install Dependencies: This mod requires CodeTalker.
- Optional UI: Install EasySettings to configure the mod in-game via the "HAC Settings" tab.
- Run & Config: Run the game once to generate the config file at
BepInEx\config\com.HardAntiCheat.sftwre.cfg, or use the in-game UI.
Dependencies & Recommendations
| Mod Name | Status | Description |
|---|---|---|
| CodeTalker | REQUIRED | Handles secure networking for mod verifications. |
| EasySettings | Recommended | Adds an in-game settings menu to configure AntiCheat on the fly. |
| PerfectGuard | Compatible | Compatible soft-dependency for additional exploit protection. |
Configuration Settings
1. General
| Setting | Default | Description |
|---|---|---|
Enable AntiCheat |
✅ | Master switch to enable or disable all anti-cheat modules. |
Disable Detections for Host |
✅ | If true, the player hosting will not be checked. |
Trusted SteamIDs |
Comma-separated list of 64-bit SteamIDs for users who are exempt from checks. | |
Banned SteamIDs |
Comma-separated list of SteamIDs that are banned from joining immediately. | |
Verification Timeout |
25.0 | Seconds the server waits for a client to send their mod list before assuming vanilla. |
Max Log File Size (MB) |
5 | Archives the infraction log on startup if it exceeds this size. |
2. Mod Lists
Configure which mods are allowed, required, or forbidden. All GUIDs are case-insensitive.
| Setting | Default | Description |
|---|---|---|
Enable Required Mods |
❌ | If true, clients MUST have the mods listed in Required Mod GUIDs or be kicked. |
Required Mod GUIDs |
Comma-separated list of Mod GUIDs that clients must have (e.g. com.myserver.requiredmod). |
|
Enable Mod Blacklist |
❌ | If true, kicks clients who have specific GUIDs loaded. |
Blacklisted Mod GUIDs |
Comma-separated list of forbidden Mod GUIDs (e.g. com.cheat.menu). |
|
Enable Mod Whitelist |
❌ | If true, ONLY mods in the Whitelist are allowed. Any unknown mod causes a kick. Overrides blacklist when enabled. |
Whitelisted Mod GUIDs |
Comma-separated list of Mod GUIDs that are explicitly permitted. |
💡 Tip: Use
EnableModWhitelistfor tightly controlled servers. UseEnableThunderstoreWhitelist(below) for "allow all public mods" servers.
3. Thunderstore Integration
Automatically trust mods published on Thunderstore. Reduces manual whitelist maintenance.
| Setting | Default | Description |
|---|---|---|
Enable Thunderstore Whitelist |
❌ | Auto-whitelist all mods published on Thunderstore. Unknown/private mods require manual approval. |
Community Identifier |
atlyss |
Thunderstore community to fetch packages from. |
Block Deprecated Mods |
✅ | Automatically blacklist mods marked deprecated on Thunderstore. |
Refresh Interval (Minutes) |
30 | How often to refresh the Thunderstore package list. |
Cache Timeout (Hours) |
6 | How long to cache individual mod verification results. |
Auto-Whitelist New Mods |
✅ | Automatically add newly discovered Thunderstore mods to the runtime whitelist. |
Unknown Mod Grace Period |
30 | Seconds to wait for API lookup before kicking for unknown mods (only if Thunderstore whitelist is enabled). |
⚡ How It Works:
- On server start, HAC fetches all packages from your Thunderstore community.
- When a player joins, their mods are checked against this pre-loaded cache (instant).
- Unknown mods are authorized first, then verified silently in the background—no handshake timeouts.
- Verified mods are cached for future joins.
4. Remote Database
Fetch blacklists from external URLs for centralized management.
| Setting | Default | Description |
|---|---|---|
Enable Remote Blacklist DB |
❌ | Fetch a list of blacklisted mods from a URL. |
Remote Blacklist DB URL |
URL to a raw text file containing blacklisted Mod GUIDs (one per line, # for comments). |
5. Movement Detections
Validates player position and physics to prevent speed, teleport, and fly hacking.
| Setting | Default | Description |
|---|---|---|
Enable Teleport Checks |
✅ | Checks if players move faster than physically possible based on distance/time. |
Max Effective Speed |
100.0 | The max speed used for distance calculations. Increase if legit skills cause rubberbanding. |
Movement Grace Buffer |
10.0 | Distance buffer to account for dashes, knockbacks, and lag spikes. |
Movement Time Threshold |
5.5 | Seconds between position samples for speed calculations. |
Teleport Threshold |
50.0 | Distance instantly flagged as a "Teleport" rather than a speed violation. |
Enable Fly Checks |
✅ | Detects players airborne for too long (10s limit) or exceeding max height. |
Enable Speed Stat Checks |
✅ | Prevents players from illegally modifying their base movement speed stat. |
Speed Check Cooldown |
2.0 | Seconds between logging repeated speed violations from the same player. |
Jump Check Cooldown |
2.0 | Seconds between logging repeated jump violations. |
Airborne Check Cooldown |
10.0 | Seconds between logging repeated fly violations. |
Jump Threshold |
8 | Maximum consecutive jumps allowed before needing to touch the ground. |
6. Stats & XP
Validates character progression and resource gain.
| Setting | Default | Description |
|---|---|---|
Enable XP Checks |
✅ | Prevents players from gaining impossible amounts of XP. |
Max XP Gain |
1000000 | Max XP allowed in a single transaction/kill. |
Max XP Rate |
5000000 | Max total XP allowed within the defined time window. |
XP Window |
30.0 | Time window (seconds) for the XP Rate check. |
Join Window (Seconds) |
10.0 | After a player's stats first load, their saved XP, level, attribute and skill values are accepted as-is and not checked. Prevents false flags when a character joins. |
Enable Attribute Point Checks |
✅ | Blocks attribute point requests that spend more points than the player has, lower a stat, or raise a stat by more than was paid for. Nothing is reset or refunded. |
Enable Attribute Budget Check |
✅ | Flags players whose total attribute points exceed what their level allows. |
Attribute Budget Action |
Log Only |
What happens when the budget is exceeded: Log Only, Infraction (counts toward auto-punish), or Reset (infraction plus a respec with full refund). |
Attribute Budget Tolerance |
0 | Extra points allowed above the budget before a player is flagged (0-50). |
Enable Skill Point Budget Check |
✅ | Flags players whose unlocked skills cost more skill points than their level allows. |
Skill Point Budget Action |
Log Only |
What happens when the budget is exceeded: Log Only, Infraction (counts toward auto-punish), or Reset (infraction plus a skill point reset with full refund, carried out by the player's client). |
Skill Point Budget Tolerance |
0 | Extra skill points allowed above the budget before a player is flagged (0-50). |
In the
.cfgfile the Stats settings are in the[7. Stats]section.
⚡ How the Attribute Budget Works:
- The allowed total is the game's own budget:
(level - 1) * attribute points per level + 6(exactly 6 at level 1). The level is capped at the game's max level, so a forged level cannot buy extra budget.- HAC adds the player's unspent points to the points already in stats (each stat's value minus 1, since stats start at 1 after a reset) and compares the total to that budget.
- It checks after the join window and spawn grace period, right after every attribute point request, and every 2 seconds. Each violation is reported once per episode.
Trusted SteamIDsand the host (whenDisable Detections for Hostis on) are skipped.Resetsets every stat back to 1 and refunds the player's full legitimate points, so it is a respec, not a wipe. UseLog Onlyfirst and compare the logged totals with known-good characters before enforcing.
⚡ How the Skill Point Budget Works:
- The game keeps unspent skill points on the player's client, so the server cannot see them. HAC judges what it can see: the skills the client reports as unlocked.
- Each distinct unlocked skill is priced with its own skill point cost, and the total is compared to what the level has handed out:
(level / 2, rounded down) * skill points per level, because skill points are granted on even levels. The level is capped at the game's max level, so a forged level cannot buy extra budget.- It checks after the join window and spawn grace period, right after a client reports its skills (on join and after every unlock), and every 2 seconds. A violation is reported at most once every 30 seconds.
Trusted SteamIDsand the host (whenDisable Detections for Hostis on) are skipped. It works anywhere, not only in safe zones.Resetruns the game's own skill point reset (the one used on class change): the player's client locks every skill and refunds all of their legitimate points, and their active status conditions are cleared. The reset runs on the player's own client, so a modified client can ignore it; such a player keeps being reported until auto-punish steps in. UseLog Onlyfirst and compare the logged totals with known-good characters before enforcing.Not covered: unspent skill points that are never spent (the server cannot see them), and casting a skill that was never unlocked.
7. Combat & Spam
Enforces cooldowns and prevents macro-spamming of items and actions.
| Setting | Default | Description |
|---|---|---|
Enable Cooldown Checks |
✅ | Prevents using skills faster than their base cooldowns allow. |
Enable Revive Checks |
✅ | Prevents players from calling self-revive or replenish without authorization (Angela's Tear). |
Enable Spam Checks |
✅ | Master switch for input rate limiting (Items, Swaps, Blocks). |
Min Consumable Interval |
0.4 | Minimum seconds between using items (prevents potion spam macros). |
Min Weapon Swap Interval |
0.25 | Minimum seconds between weapon swaps. |
Min Block Interval |
0.1 | Minimum seconds between block inputs (Prevents "Perfect Guard" bots). |
8. Punishments
Configure automatic server actions for players who accumulate too many infractions.
| Setting | Default | Description |
|---|---|---|
Enable Auto-Punish |
✅ | Automatically kicks or bans players after the limit is reached. |
Infractions Limit |
5 | Number of warnings allowed before action is taken. |
Action Type |
Kick |
The action to take (Kick or Ban). |
9. Logging
| Setting | Default | Description |
|---|---|---|
Enable Detailed Logs |
✅ | Master switch for detailed infraction logs. |
Log Player Name |
✅ | Include player nickname in logs. |
Log Player ID |
✅ | Include SteamID/netId in logs. |
Log Infraction Count |
✅ | Show warning count (e.g. Warning 3/5) in logs. |
Log Infraction Details |
✅ | Include technical details of the violation. |
10. Connection Limit
Stops one Steam account from holding several connections to your server at once (for example multi-client "cloner" mods). It runs on the host only, so clients do not need HAC installed. In the .cfg file this is the [11. Connection Limit] section.
| Setting | Default | Description |
|---|---|---|
Enable Connection Limit |
✅ | Master switch for the connection limit. Turns off both the accept-time guard and the periodic scan. |
Max Connections Per Steam ID |
1 | Connections allowed per Steam ID (1-16). Going over the limit triggers the action below. |
Kick All Connections On Violation |
✅ | When a Steam ID goes over the limit, disconnect every connection it has, including the original. If off, only the newest extras are refused or dropped and the oldest are kept. |
Enforce Limit At Accept |
✅ | Applies the limit the moment a connection arrives, before the game sees it, instead of waiting for the next scan. |
Scan Interval (Seconds) |
0.25 | How often connections are checked while hosting (0.05-5). Config file only. |
Log Only (Test Mode) |
❌ | Only logs violations and disconnects nobody (the accept guard lets the connection through). Turn this on to test before enforcing. |
⚡ How It Works:
- Accept time: when Steam reports a new incoming connection, HAC counts how many connections that Steam ID already has (including ones mid-connect). If it is already at the limit, the new connection is closed before NextServer accepts it, so Mirror and the game never see it. With
Kick All Connections On Violationon, the Steam ID's existing connections are dropped too.- Scan: every scan, HAC also groups active connections by Steam ID and disconnects the offending connections if a Steam ID has more than the allowed number (all of them by default, or only the newest extras if
Kick All Connections On Violationis off).- Your own connection and
Trusted SteamIDsare never touched.- If a connection address is not a SteamID64, the scan skips it (and logs once) so players sharing an IP are not grouped.
The accept-time layer hooks the FizzySteamworks transport (
NextServer). If it cannot bind to the transport it logs an error and disables itself, and the scan keeps working.The limit only runs while
Enable AntiCheatis on.
Example Config Snippets
Allow All Thunderstore Mods + Block Known Cheats
[2. Mod Lists]
Enable Mod Blacklist = true
Blacklisted Mod GUIDs = com.cheat.menu,com.speedhack.mod,com.fly.hack
[4. Thunderstore]
Enable Thunderstore Whitelist = true
Community Identifier = atlyss
Block Deprecated Mods = true
Auto-Whitelist New Mods = true
Require Specific Mods + Strict Whitelist
[2. Mod Lists]
Enable Required Mods = true
Required Mod GUIDs = com.myserver.coremod,com.myserver.mapfix
Enable Mod Whitelist = true
Whitelisted Mod GUIDs = com.myserver.coremod,com.myserver.mapfix,com.myserver.qol
Trusted Admins + Live Reload
[1. General]
Trusted SteamIDs = 76561198012345678,76561198098765432
# Then use EasySettings UI to add/remove without restarting!
Attribute Budget (Test First, Then Enforce)
[7. Stats]
Enable Attribute Budget Check = true
# Start with "Log Only", then switch to "Infraction" or "Reset" once the logged totals look right
Attribute Budget Action = Log Only
Attribute Budget Tolerance = 0
Skill Point Budget (Test First, Then Enforce)
[7. Stats]
Enable Skill Point Budget Check = true
# Start with "Log Only", then switch to "Infraction" or "Reset" once the logged totals look right
Skill Point Budget Action = Log Only
Skill Point Budget Tolerance = 0
Connection Limit (Test First, Then Enforce)
[11. Connection Limit]
Enable Connection Limit = true
Max Connections Per Steam ID = 1
Enforce Limit At Accept = true
# Start with true to only log, then set to false to enforce
Log Only (Test Mode) = true
Troubleshooting
❓ "Player kicked for unknown mod but it's on Thunderstore!"
- Ensure
EnableThunderstoreWhitelistis enabled. - Check
ThunderstoreCommunitymatches your server's community (default:atlyss). - Wait ~30 seconds after server start for the initial cache fetch.
- Check logs for
[HAC] Thunderstore database initialized with X known packages.
❓ "Vanilla players getting kicked on timeout!"
- Ensure
EnableRequiredModsis false if you want to allow vanilla clients. - Vanilla clients don't respond to the mod request—they time out and are auto-authorized.
❓ "Settings not applying after edit!"
- If using EasySettings: Click "Apply Settings" in the HAC tab.
- If editing
.cfgmanually: Ensure the file is saved and not open in another program. - Check logs for
[HAC] Settings applied and reloaded successfully.
❓ "GUID not matching even though it's in the list!"
- All GUID lists are case-insensitive now.
Com.MyMod=com.mymod. - Ensure no extra spaces:
com.mod1, com.mod2→com.mod1,com.mod2(or trim spaces).
❓ "A player was disconnected when rejoining quickly!"
- Their old connection may not have timed out yet, so the new one counted as a second connection.
- With
Kick All Connections On Violationon, both the stale and the new connection are dropped. Rejoining a few seconds later works once the stale one is gone. - To tolerate quick rejoins, raise
Max Connections Per Steam IDto2, or turnKick All Connections On Violationoff so the original connection is kept.
❓ "Log says a connection address is not a SteamID64!"
- The connection limit skips addresses that are not a SteamID64 so players sharing an IP are not grouped together.
- Those connections are not limited. Report it on the Discord with the address shown in the log.
❓ "A legitimate player was flagged for Attribute Budget!"
- Check the log line: it shows the player's total and the budget for their level. A small gap usually means a character that predates a game update or a mod that changes points per level.
- Raise
Attribute Budget Toleranceto cover it, or keep the action onLog Only. Resetrefunds all of a player's legitimate points, but they lose their current build, so only use it once the logs look clean.
❓ "A legitimate player was flagged for Skill Point Budget!"
- Check the log line: it shows what the player's unlocked skills cost and what their level pays for.
- A skill that is unlocked without spending points but still carries a point cost (for example one granted another way, such as a racial or bonus skill) would count against the budget. Raise
Skill Point Budget Toleranceto cover it, or keep the action onLog Only. Resetlocks every skill and refunds all of a player's points, but they have to pick their skills again and their active status conditions are cleared, so only use it once the logs look clean.Resetruns on the player's own client. If a player stays over budget after it, their client ignored it; they keep being reported and auto-punish handles the rest.
Log Examples
✅ Successful Join (Thunderstore Mod)
[Info :HardAntiCheat] [HAC] Auto-discovered mod 'Tome (cc8615a7-47a4-4321-be79-11e36887b64a) v2.4.1' on Thunderstore and whitelisted it.
[Info :HardAntiCheat] [HAC] Player authorized. 0 mods queued for background Thunderstore verification.
⚠️ Kick Message (Human-Readable)
[Warning:HardAntiCheat] [HAC] Kicking Brook. Reason: Unauthorized/Blacklisted Mods Detected: CheatMenu_Public (0a26c5bd-f173-47f8-8f50-006dd6806ce6) v1.4.2
[Info : Console] [17:39] [HAC]: Kicked Brook. Unauthorized/Blacklisted Mods Detected: CheatMenu_Public (0a26c5bd-f173-47f8-8f50-006dd6806ce6) v1.4.2
[Info : Chat] [HAC] Brook was kicked: Unauthorized/Blacklisted Mods Detected: CheatMenu_Public (0a26c5bd-f173-47f8-8f50-006dd6806ce6) v1.4.2
🎮 Vanilla Client Join
[Info :HardAntiCheat] [HAC] Client 76561199890568449 timed out. Assumed Vanilla. Allowing join.
🔗 Connection Limit
[Info :HardAntiCheat] [HAC] [ConnLimit] New connection 3 from SteamID 76561190000000000
[Warning:HardAntiCheat] [HAC] [ConnLimit] SteamID 76561190000000000 has 3 connections (max 1). Disconnecting connection 5.
[Warning:HardAntiCheat] [HAC] [ConnLimit] SteamID 76561190000000000 has 3 connections (max 1). Disconnecting connection 6.
🚪 Limit Enforced At Accept
[Warning:HardAntiCheat] [HAC] [AcceptGuard] SteamID 76561190000000000 already has 1 connection(s) (max 1). Refusing it and dropping all of this Steam ID's connections.
📊 Attribute Budget
[Warning:HardAntiCheat] [HAC] [AttrBudget] Brook (76561190000000000): Attribute points total 140 but level 20 allows 120 (unspent 4). Log-only, no action taken.
🎓 Skill Point Budget
[Warning:HardAntiCheat] [HAC] [SkillBudget] Brook (76561190000000000): Unlocked skills cost 34 skill point(s) but level 20 only pays for 20 (9 skill(s) unlocked). Log-only, no action taken.
Contributing & Support
- 🐛 Bug Reports: Open an issue on GitHub or join the Discord.
- 💡 Feature Requests: We welcome suggestions—especially for new detection types!
- 🔧 Pull Requests: Please ensure code follows the existing style and includes tests if possible.
Discord: https://discord.gg/ePhX4Fb2we
Source Layout
Main is a partial class split across files:
Main.cs plugin entry (Awake / Start)
Config/HACConfig.cs config entries, parsing, EasySettings UI
Core/ runtime state, Thunderstore, handshake, infractions, connection limiter
Networking/Packets.cs HAC_* packets
Models/Models.cs data structures and Thunderstore models
Patches/ Harmony patches grouped by topic (AcceptGuard.cs hooks the Steam transport, AttributeBudget.cs checks attribute totals, SkillBudget.cs checks the cost of unlocked skills)
Building needs a reference to FizzySteamworks.dll (in ATLYSS_Data/Managed) for the accept-time guard.
⚠️ Disclaimer: This mod is for educational and server-management purposes only. Use responsibly and respect other players' experiences. The author is not liable for misuse.
