Skip to content
 
 

Repository files navigation

TextFilter

A server-only Fabric mod that filters text in signs, books, anvil renaming, and chat messages.

Features

  • Regex filtering — whitelist and blacklist character patterns
  • Replacements — safe RE2/J regex substitutions (applied after regex filtering)
  • Chat filtering — post-verification canonical filtering compatible with chat formatters
  • Config reload — in-game via /textfilter reload
  • Bypass permissions — per-category and global bypass

Config

Config file: config/textfilter.jsonc

{
  // TextFilter configuration format. Do not change this value manually.
  "configVersion": 2,

  // Java regex matched against each UTF-16 character.
  "whitelist": "[\\u0020-\\u007e \\n § а-я іїєґ \\u00C0-\\u024F \\u2010-\\u2027 ≈≠∞±×÷€₴]",

  // Allowed characters matching this regex are removed.
  "blacklist": "[ыъэ]",

  // RE2/J regex keys and literal values, applied in order.
  "replacements": {
    "(?i)\\bxd+\\b": "😂"
  }
}
  • whitelist — regex pattern of allowed characters
  • blacklist — regex pattern of characters to remove from the whitelist
  • replacements — RE2/J regex keys and literal replacement values (applied after filtering)

JSONC line (//) and block (/* ... */) comments are supported. If the JSONC is malformed, contains invalid patterns, or uses an unsupported configVersion, startup logs the problem and uses in-memory defaults without overwriting the broken file. A failed /textfilter reload keeps the previously active configuration.

Replacement keys are case-sensitive by default. Inline (?i) enables case-insensitive matching, so the example replaces xd, XD, and xDDD with 😂. Values are always literal: $1, $, and backslashes do not expand capture groups or require config-level replacement escaping beyond normal JSON escaping.

Rules are compiled once when the mod starts or /textfilter reload succeeds, then applied globally and sequentially in JSON order. A later rule can therefore match output produced by an earlier rule. RE2/J guarantees linear-time matching and avoids catastrophic regex backtracking. It deliberately does not support lookaround or backreferences, and its \b word boundary uses ASCII word characters. Invalid or unsupported replacement patterns are rejected. Startup uses defaults and a failed reload keeps the previously active configuration.

Existing literal keys containing regex metacharacters must escape them. For example, a literal dot is written as "\\." in JSON. With many rules, each text is still scanned once per rule; combining equivalent alternatives manually can reduce passes, but may change overlap and cascade behavior.

When textfilter.jsonc does not yet exist, TextFilter imports the old textfilter.json format. Legacy replacement keys are migrated as literal patterns so their behavior does not change. The new JSONC is written through a temporary file, using an atomic move when the filesystem supports it and a replacing move otherwise. The old JSON remains untouched and is ignored afterward.

When the config is loaded, every UTF-16 symbol used in a replacement value is added to the effective in-memory whitelist. The configured whitelist string and config file are not modified. This keeps generated output such as 😂 from being removed if the text is filtered again. blacklist still has priority, so explicitly blacklisted replacement symbols are removed on a subsequent pass.

Unicode ranges reference

Range Block Includes
\u0020-\u007e Basic Latin Standard ASCII (space, letters, digits, punctuation)
\u00C0-\u024F Latin-1 Supplement + Latin Extended-A Accented European letters (À-ÿ, Ă-ž), «»°±²³µ·¹º¼½¾¿×÷
\u2010-\u2027 General Punctuation Typographic dashes, quotes, ellipsis (–—'"„…•‹›)

Interactive tool: regexr.com · Unicode blocks: compart.com
If whitelist is empty, only symbols supplied by replacement values remain allowed. Allow all symbols by putting . as the whitelist.

Chat signing and compatibility

Minecraft signs the original player input on the client. A server cannot sign modified text as that player because it does not have the player's private key. TextFilter therefore handles chat in this order:

  1. Vanilla decodes and, when a signed chat session is present, verifies the original message.
  2. TextFilter applies bypass permissions and filters the verified canonical text.
  3. An unchanged or bypassed message continues through the original vanilla signed-message path.
  4. A changed message is deliberately rebuilt as an unsigned player message with the same sender UUID and the filtered text as its canonical body.
  5. Vanilla text filtering and chat decorators run on that filtered body.

This ordering avoids mutating the inbound packet before signature verification. It also prevents formatting mods from restoring the unfiltered input by reading the original signed body. In particular, Styled Chat 2.13.0+26.2 reads canonical message content during both formatting passes, so it receives the filtered value without a direct TextFilter dependency.

Changed messages no longer carry a cryptographic player signature. Clients may mark them as not secure or hide them when configured to show only secure chat, and their chat-reporting properties differ from unchanged signed messages. The original input was verified when vanilla supplied a signed session, but the filtered replacement itself was not signed by the player. In offline or otherwise unsigned chat mode, there is no original player signature for vanilla to verify.

Other mods can still block, decorate, mask, or replace chat after TextFilter. Compatibility is not guaranteed for mods that bypass the vanilla player-chat pipeline or use a custom network protocol.

Benchmarks

Replacement scaling and allocation measurements are documented in BENCHMARKS.md. Run the JMH suite with .\gradlew.bat jmh --no-daemon --max-workers=1.

Commands

Command Permission Description
/textfilter reload textfilter.reload or OP level 4 Reload config from disk

Permissions

Permission Description
textfilter.bypass Bypass all text filtering
textfilter.signBypass Bypass sign text filtering
textfilter.bookBypass Bypass book text filtering
textfilter.anvilBypass Bypass anvil rename filtering
textfilter.chatBypass Bypass chat filtering and retain the original signed-message path
textfilter.reload Use /textfilter reload command

Uses fabric-permissions-api.
Manage permissions with LuckPerms or similar.


You can visit my contact card.
Support me here:

ko-fi monobank

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages