# Moderation

Mutes, permanent/temporary bans, IP bans, warnings with automatic escalation actions, a jail system with movement and command locks, SocialSpy/CommandSpy and vanish. All active punishments persist across restarts; expired ones are dropped on startup.

## Commands

| Command | Syntax | Permission | Default | Description |
|---|---|---|---|---|
| `/mute` | `/mute <player> [duration] [reason]` | `mod.mute` | op | Mutes chat and private messages (permanent without duration) |
| `/unmute` | `/unmute <player>` | `mod.unmute` | op | Lifts a mute |
| `/checkmute` | `/checkmute <player>` | `mod.mute` | op | Mute status, remaining time, reason, issuer |
| `/cban` | `/cban <player> [reason]` (alias `/miraban`) | `mod.ban` | op | Permanent ban, kicks instantly |
| `/ctempban` | `/ctempban <player> <duration> [reason]` (alias `/miratempban`) | `mod.tempban` | op | Temporary ban, kicks instantly |
| `/cunban` | `/cunban <player>` (alias `/miraunban`) | `mod.unban` | op | Unbans (also never-joined players via name lookup) |
| `/checkban` | `/checkban <player>` | `mod.ban` | op | Ban type, remaining time, reason, issuer |
| `/cbanip` | `/cbanip <ip\|player> [--force] [reason]` (alias `/mirabanip`) | `mod.banip` | op | Bans an IPv4 or IPv6 address or an online player's address; kicks everyone on that IP and is enforced right at login. To prevent locking yourself out, a local address (loopback/link-local, e.g. everyone behind a proxy without IP forwarding) and an address currently shared by several online players are refused unless `--force` is given |
| `/cunbanip` | `/cunbanip <ip>` (alias `/miraunbanip`) | `mod.unban` | op | Unbans an IP (deliberately no tab completion) |
| `/warn` | `/warn <player> [reason]` | `mod.warn` | op | Warning with a per-player sequential ID |
| `/warnings` | `/warnings <player>` (alias `/warns`) | `mod.warn` | op | Lists active warnings |
| `/clearwarnings` | `/clearwarnings <player>` (alias `/clearwarns`) | `mod.clearwarnings` | op | Deletes all warnings |
| `/setjail` | `/setjail <name>` | `mod.setjail` | op | Jail point at your position (max 32 characters) |
| `/deljail` | `/deljail <name>` | `mod.setjail` | op | Deletes the jail point and releases all inmates |
| `/jail` | `/jail <player> [jail] [duration] [reason]` | `mod.jail` | op | Jails (permanent without duration) |
| `/unjail` | `/unjail <player>` | `mod.unjail` | op | Releases and teleports to spawn |
| `/socialspy` | `/socialspy` | `mod.socialspy` | op | Read other players' private messages (toggle) |
| `/commandspy` | `/commandspy` | `mod.commandspy` | op | See other players' commands (toggle) |
| `/vanish` | `/vanish` (alias `/v`) | `mod.vanish` | op | Invisible: no mob aggro, no item pickup, no join/leave message |

## Additional permissions

| Permission | Default | Description |
|---|---|---|
| `mod.vanish.see` | op | Still sees vanished players (also in `/msg` tab completion) |
| `mod.bypass.mute` | false | Chats despite a mute (private messages additionally need `msg.bypass.mute`) |
| `mod.bypass.jail` | false | Moves and uses commands despite jail |

> **Note:** Vanish also hides a player from player-name tab completion, from `/ping`, `/whois` and `/seen` (which answers with the moment of vanishing as "last seen"), from `%online%` in the tab header and layout, from `<player_count>` in join/leave messages and from AFK, death and advancement messages. Players with `mod.vanish.see` still see everything.

## Duration format

For `/mute`, `/ctempban`, `/jail` and warn actions: units `s`, `m`, `h`, `d`, `w`, freely combinable (`2h30m`, `1w2d`). A plain number counts as **minutes**. Maximum 10 years; invalid inputs like `5m abc` are rejected entirely.

> **Warning:** An active mute/ban must be removed before a new one with a different reason or duration can be set. IP bans are separate from account bans: `/cunban` does not lift an IP ban.

> **Note:** Warn actions fire exactly when the threshold is reached (not on every further warning) and run through the console; simultaneous warnings trigger a threshold exactly once. Automatic actions only ever lengthen a punishment: an active longer or permanent sanction is never shortened, the action is skipped and the moderator told. For `tempban` actions a valid `duration` is REQUIRED, otherwise the action is skipped silently.

> **Note:** Both spy modes do not survive relog/restart and exclude your own messages. Messages blocked by a mute do not appear in SocialSpy. A mute only affects chat and PM commands, not signs or books. Namespaced commands (`/mira:msg`, `/authme:login`) are treated like the plain command: word filter, the mute block on PM commands, the jail allowlist and the CommandSpy blacklist apply identically.

## Jail behavior

Movement is limited to `radius` blocks around the jail point (world changes and outbound teleports are teleported back, respawn lands in jail). Only commands from `allowed-commands` work; chat is blocked with `block-chat`. Online-only jails count only time spent online, otherwise the clock also runs offline; on login an active inmate is teleported back into jail (re-jail). An expired timed jail is released on the next contact (move, command, login) and the player is told; on server stop, time served in online-only jails is credited.

## Configuration (modules/moderation.yml)

```yaml
# Enables or disables the moderation module with all commands.
enabled: true

moderation:
  warnings:
    # Days until a warning expires automatically. 0 = never.
    expiry-days: 0
    # Automatic actions at exactly reached thresholds, any number of
    # entries, sorted by threshold.
    actions:
      action1:
        threshold: 3
        # mute, tempban or ban.
        action: mute
        # Duration format. Required for tempban, empty = permanent for mute/ban.
        duration: "1h"
        reason: "Too many warnings (auto-mute)"
      action2:
        threshold: 5
        action: tempban
        duration: "1d"
        reason: "Too many warnings (auto-tempban)"
      action3:
        threshold: 7
        action: ban
        duration: ""
        reason: "Too many warnings (auto-permban)"
  jail:
    # Movement radius in blocks around the jail point.
    radius: 5.0
    # true = new jails only count time spent online.
    online-only-default: false
    # Blocks chat for inmates.
    block-chat: true
    # Allowed commands in jail (compared on the first word; the namespaced
    # form like /mira:msg counts like the plain command).
    # Same rule for the CommandSpy blacklist below.
    allowed-commands:
      - "/msg"
      - "/tell"
      - "/r"
      - "/reply"
  commandspy:
    # Commands never reported to CommandSpy (login/password).
    blacklist:
      - "/login"
      - "/register"
      - "/changepassword"
      - "/l"
      - "/reg"
  vanish:
    # true = vanish state survives restarts and relogs.
    persist: false
    # Permanent night vision (without particles) while vanished.
    night-vision: true
```

## Complete example config

```yaml
enabled: true

moderation:
  warnings:
    expiry-days: 30
    actions:
      action1:
        threshold: 3
        action: mute
        duration: "6h"
        reason: "Too many warnings"
      action2:
        threshold: 5
        action: tempban
        duration: "3d"
        reason: "Too many warnings"
      action3:
        threshold: 8
        action: ban
        duration: ""
        reason: "Permanently too many warnings"
  jail:
    radius: 10.0
    online-only-default: true
    block-chat: false
    allowed-commands:
      - "/msg"
      - "/r"
      - "/rules"
  commandspy:
    blacklist:
      - "/login"
      - "/register"
  vanish:
    persist: true
    night-vision: true
```
