SnBans
SnBans is a network-wide punishment suite: bans, mutes, permanent blacklists and alt scanning. One jar runs on both Paper 1.20.5 or newer (1.21.x included) and Velocity 3.4.0 or newer. Every command carries the same syntax, permissions and messages on both platforms. Punishment data lives in one shared SQL schema, so several servers pointed at the same MySQL share a single punishment record.
Features
- Eight sanction commands:
/ban,/ipban,/mute,/ipmuteand/blacklist, plus/unban,/unmuteand/unblacklist. Bans and mutes each have an explicit IP variant and a per-typeip-by-defaultswitch, so a plain/bancan cover the address too. A blacklist is always permanent and always covers the IP, so it takes no duration argument at all. - Two kick commands that store nothing:
/kickand/ipkickdisconnect, announce and post their webhook, and write no row - so a kick never appears in/history, has nothing to undo and never counts towards a template ladder./ipkickclears the target's last known address, which reaches their online alts even when the target is offline. Having no row is also the one limitation: on a multi-backend Paper install a kick reaches only the server it was run on, while a Velocity install is network-wide. - Escalating templates: a reason matching a
templates.ymlid takes its duration from that template's ladder. The step is picked from how many punishments of that template the player already collected, and the last step repeats for every further offence. Offences reverted by a rollback do not count toward the escalation. - Alt detection on two axes:
/altslists the accounts sharing the target's current IP, and/snbans matchlists every IP two accounts have ever shared. An automatic join scan warnssnbans.notifyholders, filtered by the states listed inalts.notify-states. On a shared MySQL both the account list and the Online marker are network-wide, so an alt connected to another backend is listed and shown as online rather than offline.alts.hiddenkeeps named accounts out of every scan a player sees, in both directions, without touching enforcement. - Network-wide punishments: on one shared MySQL the issuing server enforces immediately, and
its peers pick the row up within
sync.interval-seconds. No plugin messaging channel is involved, and a server skips its own rows so nothing is announced twice. - Three-layer visibility: a
snbans.silentgated-s/-pflag on every issue and every revert, a per-typesilent-by-default, and a per-eventbroadcasts.*toggle. A silent punishment is still reported tosnbans.notifyholders. - Attempt notices:
attempt-noticesreports the punishments players run into rather than the ones staff hand out - a ban, IP ban or blacklist refusing a login, and a mute cancelling a chat message or a blocked command. They reach the console andsnbans.notifyholders only, throttled per player byattempt-notices.cooldown-seconds, because a banned client reconnects on its own and a muted player keeps typing. The notice names the account that tried, so an IP ban reached by an alt shows the alt rather than the account on the row. - Player-facing
/helpopand/report: the two commands here a player runs, delivered to the console and tosnbans.requests.receiveholders on every server of the network and carrying the server the request was filed on - which on a proxy install is the backend the sender is standing on rather than the proxy. Throttled per player and per kind bystaff-requests.cooldown-seconds, and a throttled player is told how long is left rather than left staring at silence. - Twelve Discord webhook blocks, one per event, each with its own URL, embed and
include-silenttoggle. Staff-typed reasons arrive neutralized, so no reason can ping@everyoneor restyle your embed. The shipped file is inert until you fill a URL in. - Bulk staff rollback:
/snbans rollback <staff> <time>counts the matches first and prints the confirm command to run. Nothing is reverted untilconfirmis appended. - Bulk amnesty:
/snbans wipe <ban|mute|blacklist|all>erases every punishment of a kind that is still in force, for a season reset or a bad mass-ban. Console only, and a dry run untilconfirmis appended, with no configuration key that can skip that step. - LiteBans import:
/snbans import litebans ...reads an existing LiteBans database and writes its bans, mutes and login history into SnBans, so a network switching over keeps its record instead of starting blank. It is a dry run untilconfirmis appended, and it refuses to run twice. - Paginated lookups:
/history <player>and/staffhistory <staff>page punishment records in chat, athistory.page-sizeentries per page.
Paper or Velocity
The same jar covers two deployments, and the choice is yours:
| Deployment | Database | Notes |
|---|---|---|
| Every Paper backend | One shared MySQL (database.type: mysql) | Punishments and reverts are network-wide. Each backend needs its own server-name. |
| The Velocity proxy alone | SQLite, standalone | Logins, chat and commands are enforced at the proxy. |
Pick exactly one. Installing SnBans on the proxy and on its backends double-announces every punishment, because the backend and the proxy each announce the same event.
Backend installs stay the recommended path for mutes. Clients from 1.19.1 onward with enforced secure chat may not accept a chat message the proxy denies. Blocked commands, bans, IP bans and blacklists are enforced exactly on either deployment.
Give each backend its own server-name. It is what {server} resolves to, it is what network
presence is keyed by, and it is how /helpop and /report reach the staff of the other servers.
Cross-server punishments themselves no longer depend on it - since 1.8.2 the sync poller recognises
its own rows by row id - and SnBans warns when it detects two servers sharing a name, but the three
things above still break between them until each one is renamed.
Two behaviors differ by platform. /snbans debug and the snbans.admin.debug node are Paper only,
with no proxy counterpart. command.aliases is re-sourced on /snbans reload on both, but the proxy
does not resend its command tree to players who are already connected, so a new alias only
tab-completes for them after they reconnect.
SnBans is not Folia-compatible: plugin.yml declares no folia-supported key.
Optional integrations
SnBans runs on SnLib alone. One optional soft dependency changes its behavior when present:
- LuckPerms: enables the staff hierarchy, read from the primary group weight. A staff member needs a strictly greater weight than the target, so two members of the same rank cannot sanction each other, and the console always passes. Whether the check also covers reverts and alt lookups is configurable. Without LuckPerms the check stays off on both platforms, with a console warning rather than an error, and every rank can punish every rank.
Links
- Source and releases: part of the shared Sn-Releases repo