Skip to content

Moderation

Everything on this page lives in modules/moderation.yml, except mutes, which are commands rather than config.

plugins/Voxen/modules/moderation.yml
cooldown: 1s
cooldown-affect-pm: false
max-length:
chars: 0
affect-pm: true
anti-repeat:
enabled: false
affect-pm: false
window-seconds: 30
similarity:
enabled: false
threshold: 0.85
history: 3
anti-flood:
enabled: false
affect-pm: true
max-run: 8
max-word-length: 30
filter:
enabled: false
affect-pm: true
mode: censor
censor-char: "*"
words: []
words-file: ""
patterns: []
normalize:
leetspeak: true
diacritics: true
separators: true
repeated: true
links:
enabled: false
affect-pm: true
mode: block
ips: true
whitelist:
- youtube.com
- youtu.be
slowmode:
enabled: false
history:
enabled: false
affect-pm: false
keep-days: 14
entries: 15
chat-clear-lines: 100

Every check ships off. A fresh server does not filter, rate limit or slow anything until you flip the enabled under the check you want, and /voxen reload picks it up.

Every check on this page is written for public chat first. Each one has its own affect-pm switch that decides whether /msg and /r go through it as well, so you pick what belongs in a private conversation and what does not.

Key Default Applies to PM
cooldown-affect-pm false the delay between messages
max-length.affect-pm true the character limit
anti-repeat.affect-pm false exact and similar repeats
anti-flood.affect-pm true character runs and mashed keys
filter.affect-pm true blocked words and patterns
links.affect-pm true links and IP addresses
history.affect-pm false writing the message to the chat log

The defaults say no to the two rate limits and yes to the content checks. A conversation sends “ok” twice and answers within a second, which is not spam, but a slur or an advertised address is just as unwelcome in a PM as in chat.

The bypass permissions are the same nodes as in chat, so voxen.bypass.filter covers both. Cooldowns are shared with chat rather than counted separately, so switching cooldown-affect-pm on means a PM also delays the next public message. Mutes have their own switch, respect-mutes in modules/private-messages.yml.

With history.affect-pm on, private messages land in the same chat_log table under the channel name @pm, so /voxen history <player> shows them alongside public messages. Only the sender’s server writes the row.

max-length:
chars: 0
affect-pm: true

chars: 0 is off, which is the default. Anything above that rejects messages longer than that many characters before formatting, counted on what the player typed. The message-too-long message gets <max>.

Clients cap chat input at 256 characters anyway, so this mostly matters for messages that arrive through a command or another plugin.

Key Meaning
cooldown minimum delay between any two messages per player, empty disables it
anti-repeat.enabled blocks the same message twice within window-seconds
anti-repeat.similarity.enabled also blocks messages that are only slightly changed
anti-repeat.similarity.threshold how alike two messages must be, 0.0 to 1.0
anti-repeat.similarity.history how many recent messages each new one is compared against

With similarity off, only an exact repeat counts. With it on, hi there! right after hi there is caught too. Lower the threshold to catch more, at the cost of the occasional false positive on short messages. voxen.bypass.spam skips the check entirely, voxen.bypass.cooldown skips the delay.

Channels can have their own cooldown on top of the global one, which is the usual way to slow down a trade channel without slowing down everything.

The chat-repeat message gets <threshold>, the configured percentage, so players can see how close is too close. The same value is available anywhere else as %voxen_similarity_threshold% or <voxen_similarity_threshold>.

Key Meaning
anti-flood.enabled rejects messages that are only noise
anti-flood.max-run how many identical characters in a row are still allowed
anti-flood.max-word-length longest allowed word, 0 turns the check off

This is the one that stops aaaaaaaaaaaaaaaaaaaa and a wall of mashed keys. Two checks, both cheap and both aimed at message shape, not content:

  • a run of more than max-run of the same character. hellooooo and aaaaaaaa still pass at the default of 8, aaaaaaaaa does not.
  • a single word longer than max-word-length. Normal sentences have spaces, keyboard mash does not. Words containing ., : or / are skipped so links keep going to the link filter, where the whitelist can let them through.

voxen.bypass.spam skips it, same as anti-repeat.

Key Meaning
filter.mode block rejects the message, censor masks matches with censor-char
filter.words blocked words, matched case-insensitively
filter.words-file extra word list file, one word per line, # starts a comment
filter.patterns blocked regex patterns
filter.normalize.leetspeak matches digit and symbol swaps, so d4rn and $hoot hit
filter.normalize.diacritics strips accents, so dąrn and shoöt hit
filter.normalize.separators ignores spacing and punctuation, so d.a.r.n hits
filter.normalize.repeated collapses runs of the same letter, so daaarrn hits

words-file is a path relative to the plugin folder, which keeps a long list out of the YAML:

filter:
words-file: "blocked-words.txt"

repeated also collapses the words you listed, so daarn in the list and darn in a message match each other. The price is the occasional false positive on words that legitimately double a letter, since pass is compared as pas. Turn it off if that bites.

Matching is on substrings, not whole words, so a listed word catches anything containing it: darn also hits darned and goddarn. It does not work backwards, though, so a full form like darned misses the plain darn. List the stem and every ending follows.

filter:
words:
- darn # darn, darned, darning

This matters most in inflected languages, where one word has a dozen endings. One stem covers them all.

In censor mode, players with voxen.filter.toggle can run /filter to see the uncensored original. block mode rejects messages before they exist, so there is nothing to reveal.

plugins/Voxen/modules/moderation.yml
glyphs:
enabled: false
mode: "censor"
affects-private-messages: true

Nexo, Oraxen and ItemsAdder let players write :name: and turn it into a glyph from the resource pack, each checking its own permission before it substitutes. That check only covers the substitution. A player who copies the finished character out of chat and pastes it back is not substituting anything, so the glyph renders whatever those permissions say.

Voxen closes that by looking at the characters themselves: anything in the Unicode private use areas, which is where all of those plugins put their glyphs, is removed unless the player holds voxen.chat.glyphs. mode: block refuses the whole message instead of cleaning it, and affects-private-messages covers /msg as well.

Staff with voxen.filter.toggle see the original text, the same as with the word filter, so nothing is hidden from the people reviewing it.

Key Meaning
links.enabled the link and IP filter
links.mode block rejects the message, censor masks the link
links.ips also catches bare IPv4 addresses like 1.2.3.4:25565
links.obfuscated also catches play,server,pl, where a comma or apostrophe stands in for the dot
links.whitelist domains that stay allowed, subdomains included

obfuscated covers the usual dodge of writing play,server,pl or play'server'pl instead of dots. To keep normal sentences out of it, a match has to end in something that really looks like a domain ending (com, pl, gg, xyz and the rest of the common list) and start with at least three characters, so hello, world and no,it isn't pass. The whitelist applies here too.

It runs before the word filter and has its own bypass, voxen.bypass.links, so staff can post links while everyone else cannot. Addresses count with or without a scheme, so example.com/thing is caught. A whitelist entry matches the host and its subdomains: youtube.com also allows www.youtube.com and m.youtube.com.

/voxen slowmode global 10s
/voxen slowmode global off

Raises a channel’s cooldown at runtime. It never makes a channel faster than the cooldown in its own file, it only raises it. voxen.bypass.cooldown skips it like any other cooldown.

  1. Mute someone, optionally on one channel only:

    /voxen mute Steve 2h global spamming
    /voxen mute Steve permanent all
  2. Check what is active:

    /voxen mutes
    /voxen muteinfo Steve
  3. Lift it:

    /voxen unmute Steve all

Durations are 10m, 2h, 7d or permanent. A raw UUID works instead of a name, which covers players who have never joined this server. voxen.mute.exempt makes someone unmutable.

/voxen mutechat silences everyone at once, /voxen mutechannel <channel> silences one channel. Both have their own bypass nodes.

On a network, mutes are broadcast to every server the moment they are set. See Cross-server chat.

history:
enabled: false
keep-days: 14
entries: 15

Off by default. When enabled, messages are written to the chat_log table after they pass the filter, together with the channel and the server-id they came from, so on a network every server writes into the same log if they share a database.

/voxen history <player> shows the newest entries messages. Rows older than keep-days are deleted on startup; 0 keeps them forever.

chat-clear-lines is how many blank lines /voxen chatclear pushes. Players with voxen.mod.chatclear.exempt keep their chat visible during a global clear, so staff do not lose context. /voxen chatclear <player> clears one person.