Bans & Mutes

The punishments module provides network-wide bans and mutes with fixed reasons from reasons.yml, escalation levels, admin bans, rank protection, a player profile (/lookup), history and unban appeals in the dashboard.

Note

License: punishments is part of the free base by default (together with core, reports, lobby). Which modules are free can change – the dashboard shows locked modules grayed out.

Enabling

  • Module key: punishments (no dependencies). See Modules & Presets.
  • In a network, enable it on the proxy: the proxy registers /ban, /unban, /mute, /unmute, /lookup, /playerinfo, /history, /modify and /resethistory and executes them centrally. The Spigot variants are only the fallback for single servers.
  • The ban check on join runs on every server, even without the module.

reasons.yml

All ban and mute reasons are in one list. The reasons.yml on the proxy is authoritative: the proxy stores it in the database on startup and on /eternal reload. API/dashboard (within 30 s) and all Spigot servers (within one minute) adopt exactly this list. The file on the Spigots only applies if there is no proxy.

reasons:
  - id: 1
    type: ban
    label: "Hacking / Cheating"
    duration: permanent

  - id: 5
    type: ban
    label: "Schwere Beleidigung"
    duration: 7d
    escalation:
      - 7d          # 1st time
      - 30d         # 2nd time
      - permanent   # 3rd time and every time after

  - id: 10
    type: ban
    label: "Strafbare Inhalte"
    duration: permanent
    permission: eternal.reason.extreme

  - id: 20
    type: mute
    label: "Chat-Spam"
    duration: 1h

  - id: 90
    type: ban
    label: "Server-Sabotage"
    duration: permanent
    admin: true
FieldRequiredMeaning
idyesUnique number starting at 1. Gaps are allowed.
typeyesban (kicks, blocks joining) or mute (blocks chat). Alone decides the kind of punishment – so /ban <Spieler> 20 imposes a mute.
labelyesText on the ban screen, in the broadcast and in the history.
durationyespermanent or <n>s, <n>m, <n>h, <n>d, <n>w, <n>y.
permissionnoPermission the executor needs. Default: eternal.ban, or eternal.ban.admin with admin: true.
groupidnoMinimum rank level. Someone without the permission may still use it if their level is ≥ this value. 0 = off.
adminnotrue = admin ban: only eternal.ban.admin may impose it, only eternal.unban.admin may lift it. Read-only for normal mods in the dashboard.
escalationnoDuration per offense. Earlier, expired or lifted punishments with the same reason are counted. If there are more offenses than levels, the last one repeats. Without escalation, duration always applies.

reasons.yml also contains the report reasons (report-reasons, see Reports) and the shortening templates for unban appeals (appeal-shorten-templates, see below).

Reason permissions in the dashboard (eternal.ban.reason.<id>)

For every reason, Eternal automatically registers the permission eternal.ban.reason.<id> (category „reasons“ in the permission editor). It controls the web report flow: in the dialog „Bannen/Muten aus Report“ ("Ban/mute from report"), only reasons the staff member may use appear, and the API rejects a reason without a matching permission with 403.

A reason can be used in the dashboard if all three conditions are met:

  1. Base permission: eternal.mute (mute reason), or eternal.ban or eternal.ban.admin (depending on admin:).
  2. eternal.ban.reason.<id> – default level Team, i.e. opt-out: anyone with the base permission may use every reason until an admin sets the reason to Aus ("Off") for a rank.
  3. A permission: set in reasons.yml must also be held.

The option Sonstiges ("Other") in the dialog (free label + duration) sends no reason and only needs the base permission.

Note

In-game, the reason permissions do not count. There, /ban and /mute only check permission: (or the default) and groupid.

Commands

In a network, all commands run on the proxy. Player names are also resolved for offline players.

CommandPermissionDescription
/ban <Spieler> [Grund-Nr]eternal.banWithout a number: list of all reasons you may use. With a number ([Grund-Nr] = reason no.): punishment according to the reason's type.
/mute <Spieler> [Grund-Nr]eternal.muteLike /ban – the type comes from the reason.
/unban <Spieler> [Grund]eternal.unbanLifts the active ban ([Grund] = reason). Admin bans require eternal.unban.admin.
/unmute <Spieler> [Grund]eternal.unmuteLifts the active mute.
/lookup <Spieler>eternal.lookupProfile: UUID, rank, active punishments, latest entries.
/playerinfo <Spieler> (/pinfo, /whois)eternal.lookupCompact player info (proxy only): rank, online, last IP, active ban/mute, nick.
/history <Spieler> (/banhistory)eternal.lookupBan, mute and report history as cards.
/modify <Bann-ID> setduration <Dauer>eternal.modify.durationNew duration, counted from now (permanent allowed).
/modify <Bann-ID> setreason <Grund-ID oder Text>eternal.modify.reasonNew reason; a number takes over label and ID from reasons.yml, otherwise free text.
/resethistory <Spieler>eternal.history.resetDeletes the history (see history.reset-mode).

Everyone with eternal.notify receives notifications about new bans and mutes.

config.yml

# Behavior of /resethistory
history:
  reset-mode: hard   # hard = physically delete entries
                     # soft = keep entries with hidden=1 (restorable via SQL),
                     #        no longer count for escalation, not shown in /history

Who may punish whom (levels)

Banning and muting are rank-protected: the executor needs a strictly higher level than the target. So equal ranks cannot punish each other.

  • Level = maximum of the highest held permission eternal.tier.0 … eternal.tier.100 and the priority of the highest group (Eternal Perms, formerly CloudNet sortId).
  • If the target is offline, the last level stored in their profile counts.
  • eternal.bypass removes the protection completely. The console may always.
  • A reason's groupid uses the same level: level ≥ groupid replaces the missing reason permission.
  • In the dashboard, the /lookup view and the history are additionally rank-protected (your own level must be higher; eternal.bypass bypasses this). In-game, /lookup and /history are not rank-protected.
Warning

Without ranks with priority and without eternal.tier.* permissions, everyone has level 0 – then nobody can ban anyone. Either maintain priorities in the ranks or give staff e.g. eternal.tier.50.

Legacy: with cloudnet.legacy-mapping: true, the groups listed under cloudnet.groups are mapped by name to permissions and tier. With Eternal Perms this is not needed (default false).

Ban screen

The kick text on a ban and on a join attempt comes from translations/<sprache>.yml (<sprache> = language), key ban-kick-screen:

ban-kick-screen: |-
  &dEternal &8»

  &7Du wurdest vom Netzwerk &cgebannt&7.

  &dGrund&8: &b{reason}
  &dDauer&8: &7{duration}
  &dBann-ID&8: &c#{id}{appealBlock}

  &8Beschwerde: &f/appeal

(German default text: "You have been banned from the network. Reason / Duration / Ban ID … Appeal: /appeal".)

PlaceholderContents
{reason}Label of the reason
{duration}Remaining duration or „permanent“
{id}Ban ID (the player needs it for the appeal)
{appealBlock}Notice line after a rejected appeal, otherwise empty

The line „Beschwerde: /appeal“ ("Appeal: /appeal") refers to the appeal page in the dashboard (<Dashboard-URL>/appeal). Adjust it to your domain. Other texts: ban-broadcast, mute-blocked-chat, ban-perm-denied, unban-admin-only, tier-blocked-action.

Unban appeals

Banned players submit appeals in two ways:

  • Without login: the /appeal page in the dashboard – player name, ban ID and justification (at least 10 characters). Name and ID must match the active ban.
  • With login: Mein Konto → Entbannungsantrag stellen ("My account → Submit unban appeal"). Banned players get into the dashboard via password login (see Dashboard: login & accounts). There they also see earlier appeals and, if available, the replay of their ban.

Only one open appeal per ban is possible.

Handling (Moderation → Entbannungsanträge)

ActionPermissionEffect
View listeternal.web.dashboardOpen appeals, filter by status
Genehmigen ("Approve")eternal.web.appeals.decideThe ban is lifted
Ablehnen ("Reject")eternal.web.appeals.decideThe ban stays; the note appears on the ban screen ({appealBlock})
Verkürzen ("Shorten")eternal.web.dashboardShorten the remaining duration via a template or a custom duration

The templates come from reasons.yml:

appeal-shorten-templates:
  - id: immediate
    label: "Sofort entbannen"
    duration: 0s
  - id: 1d
    label: "Auf 1 Tag verkuerzen"
    duration: 1d
  - id: 7d
    label: "Auf 1 Woche verkuerzen"
    duration: 7d

The duration can be overridden in the dialog (1d, 6h, 30m, permanent).

Dashboard pages

PagePermissionContents
Moderation → Aktive Strafen ("Active punishments")eternal.web.dashboardActive bans and mutes; lifting with eternal.unban or eternal.unban.admin
Moderation → Entbannungsanträge ("Unban appeals")eternal.web.dashboardsee above
Spieler ("Players") → profileeternal.web.player.viewHistory, sessions, appeals, chat history
Moderation → Reportseternal.report.handleBan/mute directly from the report with eternal.ban / eternal.mute

A web ban kicks the player immediately.

Common pitfalls

  • „Für diesen Grund fehlt dir die nötige Permission“ ("You lack the required permission for this reason") – the reason has its own permission: (e.g. reason 10 requires eternal.reason.extreme) or is an admin reason.
  • „Du hast nicht den Rang, um … zu bestrafen“ ("You do not have the rank to punish …") – the target has the same or a higher level. Check the ranks' priorities.
  • Reason change does not arrive – edit reasons.yml on the proxy and run /eternal reload there. Changes on the Spigots are ignored in a network.
  • /modify setduration extends unintentionally – the new duration counts from the time of the command, not from the start of the ban.
  • Reusing IDs – changing the meaning of an existing id distorts escalation and history. Better create new reasons with a new id.
  • In-game unban and replays – replays for a ban are deleted when it is lifted via the dashboard. See Replays.
  • The permissions eternal.reportsystem and eternal.lookup.bypass (in plugin.yml and in the example under cloudnet.groups) come from older versions and are no longer checked in the code. Reports are handled with eternal.report.handle; rank protection is bypassed with eternal.bypass.