Commands
Every punishment command is registered on the velocity module (ACF/co.aikar.commands) — punishments are always issued from the proxy, never from a backend server. The paper module registers the staff-facing browsing commands (/lookup, /history, /alts, the listings), which only ever read.
Velocity commands take a MinecraftPlayer target, resolved by name via MinecraftPlayerContextResolver — this works for offline targets, not just currently-connected players. /ipban and /unban instead take a PunishmentTarget, which is either an account or a bare address (see /ipban).
Two guards run before any punishment is issued — immunity and duration limits. Both are described under Overview → Immunity and limits; a refusal answers target-exempt or duration-too-long and records nothing.
Velocity commands
Command | Aliases | Permission | Syntax |
|---|---|---|---|
| — |
|
|
| — |
|
|
| — |
|
|
| — |
|
|
|
|
|
|
| — |
|
|
|
|
|
|
| — |
|
|
Reason parsing and the -s flag
Every [reason] argument is run through ParsedReason.parse(...): the raw string is split on spaces, any -s token (case-insensitive, anywhere in the string) is stripped out and sets silent = true, and the remaining tokens are rejoined as the reason. A silent punishment still records normally and still messages the operator/target — only the network-wide broadcast is skipped.
issues a 7-day ban on Notch with reason "Griefing spawn", broadcasting nothing.
A silent punishment is still posted to Discord, marked (silencieuse) in the embed title: -s is silent towards players, not towards staff.
/ban
Permission: punishments.ban. Stateful — reissuing while Notch already has an active BAN refreshes that row (issuer, reason, expiry) instead of creating a second one. Disconnects the target immediately if they're online (best-effort — the punishment is recorded and announced regardless of whether the kick succeeds).
Arg | Type | Description |
|---|---|---|
|
| Required. Resolved by name, online or offline. |
|
| Optional. Omit for a permanent ban. See duration syntax. |
|
| Optional free text, parsed per above. |
Feedback: target-banned (operator) → target-banned-broadcast (network, unless -s) → player-banned (shown to the target on disconnect).
/ipban
Permission: punishments.ipban. Bans an address rather than (only) an account. The argument is a PunishmentTarget — either a player, or a bare IPv4/IPv6 address.
Against an account: the address is resolved as the target's live connection address if they're online on this proxy, else their last address from ip_history; if neither is available the command replies target-no-ip and issues nothing. Stateful — reissuing while the same target already has an active IPBAN refreshes that row (including the address). player_uuid is kept on the row for audit and so /unban can find it.
Against a bare address: writes the row the schema has always allowed and no command could previously reach — an IPBAN with no player_uuid, matched at login on the address alone. Re-issuing against an address that already carries a bare ban refreshes that row rather than duplicating it. Immunity is checked against every account ever seen on the address, so an address ban cannot be used to reach someone who outranks the issuer; a refusal answers target-exempt.
After saving, every session on this proxy whose current address matches the banned IP is disconnected — not just the named target, which is what catches alts sharing the address.
Arg | Type | Description |
|---|---|---|
|
| Required. A player name/UUID, or a bare address. |
|
| Optional. Omit for a permanent IP ban (subject to the issuer's cap). |
|
| Optional, parsed per above. |
Feedback: target-ipbanned (operator) → target-ipbanned-broadcast (network, unless -s) → player-ipbanned (shown to each disconnected session).
/mute
Permission: punishments.mute. Stateful — reissuing refreshes the existing active MUTE. Never disconnects the target.
Mutes are enforced on the game servers — chat and the commands listed in mute.yml are refused for a muted player. See Overview → Mute enforcement.
Arg | Type | Description |
|---|---|---|
|
| Required. |
|
| Optional. Omit for a permanent mute. |
|
| Optional, parsed per above. |
Feedback: target-muted (operator) → target-muted-broadcast (network, unless -s). No target-facing screen.
/kick
Permission: punishments.kick. Point-in-time — always creates a new row, never reissues. Unlike /ban//ipban, the disconnect is required: if the target isn't currently online the command replies player-not-online and records nothing.
Arg | Type | Description |
|---|---|---|
|
| Required; must be online. |
|
| Optional, parsed per above. |
Feedback: the target is disconnected first (player-kicked screen); only once the disconnect succeeds is the record saved, target-kicked sent to the operator and player-kicked-broadcast announced (unless -s).
/warn
Permission: punishments.warn. Point-in-time, never disconnects, no broadcast. reason is required; an optional duration may precede it.
A warning stands until it expires or is lifted: the duration given, else the warnings.yml default, else permanently. Duration caps do not apply — a warning is a record rather than a restriction.
The target is told about it: immediately if they are connected anywhere on the network, otherwise on their next login (player-warned, with %reason% and %source%). Delivery is recorded on the row so it is never repeated — see Overview → Warning delivery.
Arg | Type | Description |
|---|---|---|
|
| Required. |
|
| Optional. Omit to use the configured default. |
|
| Required, parsed per above. |
Feedback: target-warned (operator) → player-warned (target, now or on next login).
/unwarn
Permission: punishments.unwarn. Lifts the most recent warning still standing against the target — one per invocation. Replies target-not-warned when there is none.
Arg | Type | Description |
|---|---|---|
|
| Required. |
|
| Optional pardon reason, parsed per above — recorded as |
Feedback: target-unwarned (operator) → target-unwarned-broadcast (network, unless -s).
/unban (/pardon)
Permission: punishments.unban. Given a player, looks up their latest active BAN and latest active IPBAN in parallel and pardons whichever exist; given a bare address, lifts the ban on that address — a target with both an account ban and an IP ban tied to their UUID has both lifted by one command. If neither is active, replies target-not-banned.
Arg | Type | Description |
|---|---|---|
|
| Required. A player, or a bare address to lift a bare-address ban. |
|
| Optional pardon reason, parsed per above — recorded as |
Feedback: target-unbanned (operator) → target-unbanned-broadcast (network, unless -s).
/unmute
Permission: punishments.unmute. Same shape as /unban but only for MUTE. Replies target-not-muted if none is active.
Arg | Type | Description |
|---|---|---|
|
| Required. |
|
| Optional pardon reason, parsed per above. |
Feedback: target-unmuted (operator) → target-unmuted-broadcast (network, unless -s).
Duration syntax
Duration arguments (/ban, /ipban, /mute, /warn) are parsed by DurationContextResolver → DurationParser.parse(...), which accepts one or more <number><unit> tokens (optionally space-separated, combined additively) using units y (365-day years), d, h, m (minutes), s, and ms. An optional duration that does not parse is not an error: the argument is left in place for the reason to pick up, so /ban Steve griefing spawn works as written. A duration argument that is required still fails loudly.
Paper commands
All of these are player-only (they open a menu) and read-only — nothing here issues or lifts a punishment except the pardon button inside the history GUI.
Command | Aliases | Permission | Syntax |
|---|---|---|---|
| — |
|
|
|
|
|
|
|
|
|
|
| — |
|
|
| — |
|
|
| — |
|
|
| — |
|
|
Every <player>/<staff> argument completes from @offlinePlayers and resolves offline accounts.
/lookup
Opens the lookup hub — one menu routing to the target's punishment history, linked accounts and address history, each button showing how many entries it holds.
/history
Opens the punishment history menu for <player>: every punishment ever recorded against them — active, expired and pardoned. The optional [duration] restricts the listing to punishments issued within that window; an unparseable value replies invalid-duration and opens nothing. An empty history answers no-history.
/alts
Opens the alts menu: every account that has connected from an address this one has also used, each row carrying that account's live ban/mute status. Clicking a row jumps to that account's hub. Answers no-alts when there are none.
/banlist, /mutelist, /warnlist
Open a listing of every ban / mute / warning currently in force network-wide, newest first, capped at 500 rows. Clicking a row opens that player's hub. Empty answers no-results.
/staffhistory
Opens the same listing blueprint for a different question: every punishment <staff> has issued, newest first, including lapsed and lifted ones — the point being what they handed out, not what still stands.
Permission summary
Node | Grants |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| The matching in-force listing. |
|
|
| Protection from punishment by staff at or below |
Duration ceilings are keyed on whatever permission each tier in limits.yml names; there is no fixed node.
See also
Overview — stateful vs. point-in-time punishments, cross-server sync.
Configuration — the
messages.ymlkey catalogue backing every reply above, pluslimits.yml,warnings.yml,discord.ymlandmute.yml.Staff menus — what the paper commands open.