Add ability to configure profanity filter exceptions

Fix minor bug where color codes counted for censored word length
This commit is contained in:
Goodlyay 2025-02-10 05:01:25 -08:00
parent ba80413526
commit 04d100393c
3 changed files with 55 additions and 27 deletions

View File

@ -24,7 +24,8 @@ using MCGalaxy.Util;
namespace MCGalaxy {
public static class ProfanityFilter {
static string[] reduceKeys, reduceValues;
static List<string> filters;
static List<string> goodWords;
static List<string> badWords;
static bool hookedFilter;
public static void Init() {
@ -37,28 +38,31 @@ namespace MCGalaxy {
string[] words = text.SplitSpaces();
string[] reduced = Reduce(text).SplitSpaces();
// Loop through each reduced word, looking for a bad word
for (int i = 0; i < reduced.Length; i++)
{
bool isFiltered = false;
foreach (string filter in filters)
{
if (reduced[i].Contains(filter)) {
isFiltered = true; break;
for (int i = 0; i < reduced.Length; i++) {
foreach (string goodWord in goodWords) {
// If the word is a good word, skip bad word check
if (Colors.Strip(words[i].ToLower()) == goodWord) {
goto nextWord;
}
}
if (!isFiltered) continue;
// If a bad word is found anywhere in the word, replace the word
words[i] = Replace(words[i]);
foreach (string badWord in badWords) {
if (reduced[i].Contains(badWord)) {
// If a bad word is found anywhere in the word, replace the word
words[i] = Censor(Colors.Strip(words[i]).Length);
goto nextWord;
}
}
// This is more readable than the previous implementation. Don't @ me
nextWord:;
}
return String.Join(" ", words);
}
static string Replace(string word) {
static string Censor(int badWordLength) {
string replacement = Server.Config.ProfanityReplacement;
// for * repeat to ****
return replacement.Length == 1 ? new string(replacement[0], word.Length) : replacement;
return replacement.Length == 1 ? new string(replacement[0], badWordLength) : replacement;
}
static void InitReduceTable() {
@ -70,23 +74,27 @@ namespace MCGalaxy {
}
static void LoadBadWords() {
TextFile filterFile = TextFile.Files["Profanity filter"];
filterFile.EnsureExists();
// Duplicated literal const values? tsk x1000
TextFile goodWordsFile = TextFile.Files["Profanity filter exceptions"];
TextFile badWordsFile = TextFile.Files["Profanity filter"];
goodWordsFile.EnsureExists();
badWordsFile.EnsureExists();
if (!hookedFilter) {
hookedFilter = true;
filterFile.OnTextChanged += LoadBadWords;
badWordsFile.OnTextChanged += LoadBadWords;
}
string[] lines = filterFile.GetText();
filters = new List<string>();
// Run the badwords through the reducer to ensure things like Ls become Is and everything is lowercase
foreach (string line in lines)
{
if (line.StartsWith("#") || line.Trim().Length == 0) continue;
goodWords = goodWordsFile.GetTextWithoutComments();
badWords = badWordsFile.GetTextWithoutComments();
string word = Reduce(line);
filters.Add(word);
// Convert all goodwords to lowercase to make later comparisons simpler
for (int i = 0; i < goodWords.Count; i++) {
goodWords[i] = goodWords[i].ToLower();
}
// Run the badwords through the reducer to ensure things like Ls become Is and everything is lowercase
for (int i = 0; i < badWords.Count; i++) {
badWords[i] = Reduce(badWords[i]);
}
}

View File

@ -27,6 +27,7 @@ namespace MCGalaxy
public const string TempBansFile = "text/tempbans.txt";
public const string CustomTokensFile = "text/custom$s.txt";
public const string BadWordsFile = "text/badwords.txt";
public const string BadWordsExceptionsFile = "text/badwords_exceptions.txt";
public const string EatMessagesFile = "text/eatmessages.txt";
public const string RulesFile = "text/rules.txt";
public const string OprulesFile = "text/oprules.txt";

View File

@ -51,6 +51,19 @@ namespace MCGalaxy.Util
public string[] GetText() {
return File.ReadAllLines(Filename);
}
/// <summary>
/// Returns all text lines in the file that do not begin with # and are not empty.
/// </summary>
/// <returns></returns>
public List<string> GetTextWithoutComments() {
string[] lines = GetText();
List<string> text = new List<string>();
foreach (string line in lines) {
if (line.StartsWith("#") || line.Trim().Length == 0) continue;
text.Add(line);
}
return text;
}
public void SetText(string[] text) {
File.WriteAllLines(Filename, text);
@ -75,6 +88,12 @@ namespace MCGalaxy.Util
{ "Profanity filter", new TextFile(Paths.BadWordsFile,
"# This file is a list of words to remove via the profanity filter",
"# Each word to remove must be on an individual line") },
{ "Profanity filter exceptions", new TextFile(Paths.BadWordsExceptionsFile,
"# This file is a list of words that the profanity filter will not filter,",
"# even when part of the word has been added to "+Paths.BadWordsFile,
"# This allows mitigation of the \"Scunthorpe problem\" on a case-by-case basis.",
"# For instance, one may want to block the word \"Thor\", but allow the word \"Scunthorpe\".",
"# Each word to allow must be on an individual line") },
{ "Announcements", new TextFile(Paths.AnnouncementsFile, null) },
{ "Joker", new TextFile(Paths.JokerFile, null) },
{ "8ball", new TextFile(Paths.EightBallFile,