From b5230d728cd2ad79028d031144c098bff2c96251 Mon Sep 17 00:00:00 2001 From: AyeZeeBB Date: Fri, 9 Oct 2026 21:59:10 -0500 Subject: [PATCH] Words not allowed in chat are blocked whatever word_warnings is A dedicated server with word_warnings set to 0 passed such messages on. It now never does: at 0 the message is dropped, its player is told it was not sent, and nobody is warned or kicked. The team's lists are read on every server for this, including one with use_global_bans off, which still lets globally banned players in. --- Extension/Multiplayer/word_lists.h | 3 +++ Server/README.txt | 11 ++++++----- Server/main.cpp | 14 ++++++++------ Server/server_config.h | 6 +++--- Server/server_host.cpp | 8 +++++++- 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/Extension/Multiplayer/word_lists.h b/Extension/Multiplayer/word_lists.h index 31845210..7133dd37 100644 --- a/Extension/Multiplayer/word_lists.h +++ b/Extension/Multiplayer/word_lists.h @@ -24,4 +24,7 @@ inline constexpr unsigned word_warnings_default = 3, word_warnings_most = 10; inline constexpr std::string_view word_kick_notice = "Kicked for using words that are not allowed here."; // What the player is told at their `count`th warning of `warnings`. std::string word_warning(unsigned count, unsigned warnings); +// And where nobody is warned or kicked (a server's "word_warnings": 0): the message is still +// not passed on. +inline constexpr std::string_view word_blocked_notice = "Your message was not sent: it has a word that is not allowed here."; } // namespace dingosdk::multiplayer diff --git a/Server/README.txt b/Server/README.txt index 0ced175f..7013c19a 100644 --- a/Server/README.txt +++ b/Server/README.txt @@ -122,11 +122,12 @@ afk_kick_minutes Remove a player who has been away this many minutes, 1-1440 never removed for it. Console: afk-kick |off. word_warnings The ReSkate team keeps a list of words that are not allowed in chat at all (read from api.reskate.dev with the global - bans). A message with one is not passed on, and its player - is warned. After this many warnings, 1-10 (default 3), the - next one gets them kicked; they can join again, and are - kicked again at the next. Warnings last until the server - restarts. 0: such messages are passed on like any other. + bans). A message with one is never passed on, whatever + this is set to, and its player is warned. After this many + warnings, 1-10 (default 3), the next one gets them kicked; + they can join again, and are kicked again at the next. + Warnings last until the server restarts. 0: nobody is + warned or kicked; the message is still not passed on. allow_voice_chat Allow voice chat. voice_range How far proximity voice reaches, 50-1000 m. object_placement everyone, admins (only admins can build), or nobody. diff --git a/Server/main.cpp b/Server/main.cpp index 9ab7fc11..5638c57a 100644 --- a/Server/main.cpp +++ b/Server/main.cpp @@ -478,7 +478,8 @@ int run(int argc, char **argv, bool skip_update) { std::future update_check; bool update_now{}, update_waiting{}, restart{}; // The backend's ban list (global_bans.h): read now and every ten minutes, a minute after a - // failure. "global_bans": false leaves it unread and lets those players in. + // failure. "global_bans": false lets those players in; the answer is still read, for the + // chat word lists that come in it. std::future ban_check; auto next_ban_check = next_advertise; bool bans_unread{}; @@ -552,8 +553,9 @@ int run(int argc, char **argv, bool skip_update) { } update_now = false; } - // (The chat word lists come in the same answer, so it is read for them too.) - if ((config.global_bans || config.word_warnings) && !ban_check.valid() && now_time >= next_ban_check) + // (The chat word lists come in the same answer, and hold on every server: it is read + // for them whether or not the bans are used.) + if (!ban_check.valid() && now_time >= next_ban_check) ban_check = std::async(std::launch::async, read_global_bans); if (ban_check.valid() && ban_check.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { const auto check = ban_check.get(); @@ -564,10 +566,10 @@ int run(int argc, char **argv, bool skip_update) { if (check.ok && check.words_changed) write_log("Word lists: " + std::to_string(check.filtered_words) + " filtered and " + std::to_string(check.forbidden_words) + " not allowed at all, from the ReSkate team's lists." + - (config.word_warnings ? "" : " (\"word_warnings\" is 0: nobody is warned or kicked for them here.)")); + (config.word_warnings ? "" : " (\"word_warnings\" is 0: a message with one is not passed on, and nobody is warned or kicked.)")); else if (!check.ok && !bans_unread) - write_log("The global ban list could not be read (" + check.problem + "). Trying again every minute; " + - "until then the bans already read hold."); + write_log("The ReSkate team's lists (global bans and chat words) could not be read (" + check.problem + + "). Trying again every minute; until then the ones already read hold."); bans_unread = !check.ok; } if (update_waiting && !restart && host.players() == 0) { diff --git a/Server/server_config.h b/Server/server_config.h index 6e063da1..b334f0f6 100644 --- a/Server/server_config.h +++ b/Server/server_config.h @@ -113,9 +113,9 @@ struct ServerConfig { // Minutes a player may be away (not moving, talking, typing or building) before the server // removes them, 1 to 1440; 0: never. Admins are never removed for it. unsigned afk_kick = 0; - // A chat message with a word the ReSkate team does not allow at all (word_lists.h) is not - // passed on and its player warned; after this many warnings, 1 to 10, the next gets them - // kicked. 0: such messages are passed on like any other. + // A chat message with a word the ReSkate team does not allow at all (word_lists.h) is never + // passed on. Its player is warned; after this many warnings, 1 to 10, the next gets them + // kicked. 0: nobody is warned or kicked, and the message is still not passed on. unsigned word_warnings = 3; // Players whose game runs fast (a speedhack; Server/speed_check.h): "warn" takes them out of // throwdowns and coop challenges and tells the admins, "kick" also removes them, "off" does not check. diff --git a/Server/server_host.cpp b/Server/server_host.cpp index 8654dd94..ea231d30 100644 --- a/Server/server_host.cpp +++ b/Server/server_host.cpp @@ -701,7 +701,13 @@ void Host::send_chat(std::string_view text, Guest *only) { else broadcast(message, true, false); } bool Host::allowed_words(Guest &guest, std::string_view text) { - if (!config_.word_warnings || !text::contains_forbidden_words(text)) return true; + if (!text::contains_forbidden_words(text)) return true; + // Never passed on. Without warnings ("word_warnings": 0) that is all that happens. + if (!config_.word_warnings) { + log_("[words] " + guest_name(guest) + " said a word that is not allowed; the message was not passed on."); + send_chat(multiplayer::word_blocked_notice, &guest); + return false; + } const auto id = guest.member.id; const auto count = ++word_warnings_[id]; if (count > config_.word_warnings) {