mirror of
https://github.com/Dingo-Shenanigans/ReSkate.git
synced 2026-10-17 18:37:07 +02:00
The bad-word list now comes from the ReSkate backend's Words page, in the same /api/v1/steam-ids answer the game and servers already read. It has two lists: filtered words, and words not allowed in chat at all. Until the backend has any words the built-in list stays in use; once it does, its lists replace the built-in one. Filtered words work as before: masked for players with the chat filter on, and not allowed in server or lobby names. Words not allowed at all are filtered the same way, and a chat message with one is not passed on. Its player is warned each time, and after three warnings the next one gets them kicked. Dedicated servers: new players setting word_warnings (default 3, 1 to 10, 0 switches the rule off). The count lasts while the server runs, so a kicked player who joins again is kicked at their next one. Party chat and commands are checked too, and each warning and kick is logged under [words]. The lists are read whenever global bans or word warnings are on. Player lobbies: the host's game applies the same rule to its guests, with three warnings.
53 lines
2.1 KiB
C++
53 lines
2.1 KiB
C++
#include "word_lists.h"
|
|
#include "Engine/Core/Json/json.h"
|
|
#include "Engine/Core/Text/word_filter.h"
|
|
#include <mutex>
|
|
#include <optional>
|
|
#include <stdexcept>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
namespace dingosdk::multiplayer {
|
|
namespace {
|
|
// A list is at most this many words of this many bytes: what the panel takes, and a bound on
|
|
// what an answer can make the filter hold.
|
|
constexpr std::size_t most_words = 5000, longest_word = 64;
|
|
|
|
std::vector<std::string> read(const Json &answer, const char *name) {
|
|
std::vector<std::string> words;
|
|
if (!answer.contains(name)) return words;
|
|
const auto &listed = answer.at(name);
|
|
if (!listed.is_array()) throw std::runtime_error("a word list is not a list");
|
|
for (const auto &entry : listed) {
|
|
if (!entry.is_string()) throw std::runtime_error("a word is not text");
|
|
if (words.size() == most_words) break;
|
|
if (const auto &word = entry.string(); !word.empty() && word.size() <= longest_word) words.push_back(word);
|
|
}
|
|
return words;
|
|
}
|
|
} // namespace
|
|
|
|
WordListsRead use_word_lists(std::string_view json) {
|
|
const auto answer = Json::parse(json);
|
|
WordListsRead result;
|
|
if (!answer.is_object() || (!answer.contains("filtered_words") && !answer.contains("forbidden_words"))) return result;
|
|
auto lists = std::pair(read(answer, "filtered_words"), read(answer, "forbidden_words"));
|
|
result.given = true;
|
|
result.filtered = lists.first.size();
|
|
result.forbidden = lists.second.size();
|
|
static std::mutex mutex;
|
|
static std::optional<std::pair<std::vector<std::string>, std::vector<std::string>>> last;
|
|
std::lock_guard lock(mutex);
|
|
if (last == lists) return result;
|
|
text::set_word_lists(lists.first, lists.second);
|
|
last = std::move(lists);
|
|
result.changed = true;
|
|
return result;
|
|
}
|
|
|
|
std::string word_warning(unsigned count, unsigned warnings) {
|
|
return "Your message was not sent: it has a word that is not allowed here. Warning " + std::to_string(count) + " of " +
|
|
std::to_string(warnings) + (count >= warnings ? ". The next one gets you kicked." : ".");
|
|
}
|
|
} // namespace dingosdk::multiplayer
|