From 9658014b4f71d978efae7af019184d018157c94c Mon Sep 17 00:00:00 2001 From: Aaron Kimbrell Date: Wed, 30 Sep 2026 08:05:26 -0500 Subject: [PATCH] docs(chat-filter): block list file, portable format, phrases How to build blocklist.dcf from blocklist.txt and where it goes, the version 3 layout and hash, what happens to old files, and blocked phrases; README "This branch" line. issue 215 Co-Authored-By: Claude Opus 5.5 --- README.md | 6 +++++- docs/Dashboard.md | 36 ++++++++++++++++++++++++++++++------ docs/IssueTracker.md | 1 + 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 28728013d..8fce7d677 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,10 @@ locally. See [docs/UgcServer.md](docs/UgcServer.md). * **World hot reload:** worlds report the zone files they loaded (`.luz`, `.lvl`, triggers, terrain, navmesh); when one changes on disk, or on `/reloadworld` or the dashboard's Reload, master replaces those instances with new ones and moves their players over; properties are kept until empty instead ([docs/WorldHotReload.md](docs/WorldHotReload.md)). +* **Chat filter:** the block list and the allowed words cache (`.dcf`) are hashed with 64-bit FNV-1a, so a list works + on every platform (before, `std::hash` values made on one system never matched on another); old files are refused + with a log line. Servers build `blocklist.dcf` from a plain `blocklist.txt` next to them, and blocked entries can be + phrases. See "Block list file" in [docs/Dashboard.md](docs/Dashboard.md). * The chat server's old web API is removed; the dashboard's API covers online players, teams and announcements. ## License @@ -375,7 +379,7 @@ All listed files are required for a server to start. * masterconfig.ini * WorldServer(.exe) * worldconfig.ini -* blocklist.dcf +* blocklist.dcf (or blocklist.txt, one blocked word or phrase per line, which the servers build it from) * migrations * vanity * navmeshes diff --git a/docs/Dashboard.md b/docs/Dashboard.md index ce2934753..cc3f42889 100644 --- a/docs/Dashboard.md +++ b/docs/Dashboard.md @@ -1213,18 +1213,42 @@ character's owner sees only what is still in their mailbox. Deleting a character The **Chat Filter** page (GM 5+, `chat_filter_manage`, under Moderation) decides which words players below GM 2 may use in chat. The filter's files: `chatplus_en_us.txt` (client `res` folder) lists the words normal chat may use, -`blocklist.dcf` (next to the servers, hashes only) the words best friends' free chat may not. Approved character names -also count as allowed. Words are compared lower case, without `! ? ; . ,`. Changes apply at once in running worlds and in -the chat server's web chat; servers that start later read them. Changes are audited and go to the `moderation` webhook -event. +`blocklist.dcf` (next to the servers, hashes only) the words and phrases best friends' free chat may not. Approved +character names also count as allowed. Words are compared lower case, without `! ? ; . ,`. Changes apply at once in +running worlds and in the chat server's web chat; servers that start later read them. Changes are audited and go to the +`moderation` webhook event. + +Blocked entries can be phrases: a phrase is stopped when its words come in a row in a message, whatever the spaces and +punctuation between them, and the whole phrase is marked. Allowed entries are single words only, because normal +(whitelist) chat checks each word on its own, as the client does. + +#### Block list file + +`blocklist.dcf` is DLU's own file (the client reads no `.dcf` and doesn't hash chat words). To make or change it, put the +blocked words in `blocklist.txt` next to the servers (the build folder, beside `blocklist.dcf`): one word or phrase per +line, any case, punctuation `! ? ; . ,` ignored, blank lines skipped. The world and chat servers rebuild `blocklist.dcf` +from it when they start and it is newer than the `.dcf` (or the `.dcf` is missing or unreadable), then log how many +entries it has. With `dont_generate_dcf=1` they read `blocklist.txt` directly and write no file. `blocklist.txt` can be +removed afterwards; only the `.dcf` is needed. + +Format (little-endian): `uint32` magic `DCFB`, `uint32` version `3`, `uint32` most words in one entry, `uint64` count, +then that many `uint64` hashes, sorted. Each hash is 64-bit FNV-1a (offset basis `0xcbf29ce484222325`, prime +`0x100000001b3`) over the entry's bytes: the words lower case (ASCII), without `! ? ; . ,`, joined by one space. The +same words give the same file on every platform. The allowed words cache, `chatplus_en_us.dcf` in the client's `res` +folder, uses the same format and is built from `chatplus_en_us.txt`. + +Version 2 files (older DLU) stored `std::hash` values, which differ between compilers and platforms, so a list made on +one system never matched on another (issue 215). Servers refuse them: an old `chatplus_en_us.dcf` is rebuilt from +the `.txt`, and an old `blocklist.dcf` is logged as unreadable (free chat then stops every message) until it is rebuilt +from `blocklist.txt`. The **Word files** section shows which it is. The page has three sections: - **Test a message**: type a message, pick normal or best friends' free chat, and see whether it would be sent and why, word by word (in the file, allowed or blocked here, a character name, not allowed, in the blocked words file). Each word has a Block, Allow or Remove button. -- **Staff lists**: **Blocked** words are stopped in all chat, even where a file allows them; **Allowed** words are usable - in normal chat. Search, filter by list, 50 per page. Block, Allow (or move to the other list) and Remove each open a +- **Staff lists**: **Blocked** words and phrases are stopped in all chat, even where a file allows them (phrases are + marked **Phrase**); **Allowed** words are usable in normal chat. Search, filter by list, 50 per page. Block, Allow (or move to the other list) and Remove each open a confirmation that shows where the word stands now and, for Block and Allow, the recent chat it changes (players' chat containing it that would have been stopped, or stopped messages containing it; the newest 1000 messages with the text; needs `chat_view`). diff --git a/docs/IssueTracker.md b/docs/IssueTracker.md index 48ea6c05c..24167024a 100644 --- a/docs/IssueTracker.md +++ b/docs/IssueTracker.md @@ -10,6 +10,7 @@ State: **done** = fixed on this branch, needs an in-game check; **partial** = pa |---|---|---|---| | 159 | BUG: Brick-by-brick models are deleted instead of put away | done | `6ce261c5` fix: brick by brick and model placement work the way the client expects | | 185 | BUG: Assembly Engineer Fortress Knockback | partial | `2d76c81b` feat: server side knockback for AI moved objects | +| 215 | ENH: Bring chat filter closer to Live | partial | `c1bcda8d` fix(chat-filter): portable .dcf hashing, block list phrases; `b279d187` shipped blocklist.dcf in the portable format; `cef170ae` dashboard phrases. The block list works on every platform and takes phrases; the rest of the issue is open | | 225 | ENH: "bind_ip" config option | done | `e36f894f` feat: bind_ip setting for the server sockets | | 257 | EH: Crux Prime shields stun instead of knockback | done | `2d76c81b` feat: server side knockback for AI moved objects | | 307 | Spider Queen scream on spiderling death | done | `4900f11c` fix(scripts): the Spider Queen screams from the mountain when a spiderling dies (issue 307) |