Word filter: fewer false flags, servers' own word lists; protocol 49

The chat filter matched short listed words anywhere inside a longer one, so
entries like "gger", "spik", "crip" and "coon" in the backend's lists blocked
"bigger", "spike", "script" and "raccoon".

- A listed word of four or five letters now matches inside a longer word only
  when the rest of it is what goes around a swear word ("motherfuckers",
  "bullshit", "shithead", "shitty", "xxfuckxx"). Words of six letters or more
  still match anywhere.
- An ordinary word that equals a listed phrase without its spaces
  ("the rapist" / "therapist") no longer matches.
- bad_words.txt is gone: the filter has no words until the backend's lists
  arrive.

Dedicated servers:
- "use_global_word_filter" (default true) turns the backend's lists off for a
  server. Console: words global on|off.
- data/words_filtered.txt and data/words_blocked.txt hold a server's own
  words, read at start and by "words reload". Blocked words follow
  word_warnings. Filtered words are sent to players (new packet, kind 33),
  whose games star them for players with the chat filter on and drop them on
  leaving.

Multiplayer outfits: a player whose mods add or remove skater or board slots
no longer makes everyone look like the local player. A peer's items are put
in this game's slots by slot hash; slots the peer lacks stay empty and items
in slots this game lacks are left out.
This commit is contained in:
AyeZeeBB committed 2026-10-11 13:17:28 -05:00
1 parent f4292d6b73
commit c27d6cb053
27 files changed
+473 -492

No files matched your search

+6
View File
@@ -115,6 +115,11 @@ void Host::send_permissions(Guest &guest) {
}
if (send_packet(guest, p, true, false)) guest.permissions_sent = roles_revision_;
}
void Host::send_words(Guest &guest) {
auto p = packet(PacketKind::words, now_);
p.words = filtered_words_;
if (send_packet(guest, p, true, false)) guest.words_sent = words_revision_;
}
void Host::roles_changed() {
++roles_revision_;
++bans_revision_;
@@ -1830,6 +1835,7 @@ void Host::tick(std::uint64_t now) {
// Whoever may change the map picks from it; with map votes on, everyone completes /vote map from it.
if (!guest->maps_sent && (can(id, "map") || config_.votes.map.enabled)) send_maps(*guest);
if (guest->permissions_sent != roles_revision_) send_permissions(*guest);
if (guest->words_sent != words_revision_) send_words(*guest);
}
const bool loading = std::any_of(guests_.begin(), guests_.end(),
[](const auto &g) { return g.second->handshaken && !g.second->world_ready; });