From 344dc132f492db88cbebc66abe301aab1c29be08 Mon Sep 17 00:00:00 2001 From: starkatt85 Date: Tue, 13 Jan 2026 19:03:37 +0530 Subject: [PATCH 1/9] temp mute non suspecious players when they use n word --- build/scripts/config.js | 6 +++++- build/scripts/utils.js | 15 +++++++++++++++ src/config.ts | 5 +++++ src/utils.ts | 17 ++++++++++++++++- 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/build/scripts/config.js b/build/scripts/config.js index ff9e9d5a..e0e533ff 100644 --- a/build/scripts/config.js +++ b/build/scripts/config.js @@ -33,7 +33,7 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { return to.concat(ar || Array.prototype.slice.call(from)); }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.rules = exports.tips = exports.FColor = exports.text = exports.prefixes = exports.Gamemode = exports.FishServer = exports.mapRepoURLs = exports.Mode = exports.backendIP = exports.stopAntiEvadeTime = exports.heuristics = exports.adminNames = exports.multiCharSubstitutions = exports.substitutions = exports.bannedWords = void 0; +exports.rules = exports.tips = exports.FColor = exports.text = exports.prefixes = exports.Gamemode = exports.FishServer = exports.mapRepoURLs = exports.Mode = exports.backendIP = exports.stopAntiEvadeTime = exports.heuristics = exports.adminNames = exports.multiCharSubstitutions = exports.substitutions = exports.tempMute = exports.bannedWords = void 0; var globals_1 = require("/globals"); var ranks_1 = require("/ranks"); var funcs_1 = require("/funcs"); @@ -88,6 +88,10 @@ exports.bannedWords = { "nig" + "ger", "nig" + "ga", "ni8" + "8er", "hit" + "ler", "fa" + "gg" + "ot", "nazis", ], }; +exports.tempMute = { + // temp mutes bakas if they use n word. oof. set duration of mute here. + nwordDurationMs: funcs_1.Duration.minutes(10), +}; //for some reason the external mindustry server does not read the files correctly, so we can only use ASCII exports.substitutions = Object.fromEntries(Object.entries({ "a": "\u0430\u1E9A\u1EA1\u1E01\u00E4\u03B1@\u0101\u0103\u0105\u03AC", diff --git a/build/scripts/utils.js b/build/scripts/utils.js index 14c66b02..a4bb506b 100644 --- a/build/scripts/utils.js +++ b/build/scripts/utils.js @@ -673,6 +673,21 @@ function processChat(player, message, effects) { } Log.info("Censored message from player ".concat(player.name, ": \"").concat((0, funcs_1.escapeStringColorsServer)(message), "\"; contained \"").concat(filterTripText, "\"")); players_1.FishPlayer.messageStaff("[yellow]Censored message from player ".concat(fishPlayer.cleanedName, ": \"").concat(message, "\" contained \"").concat(filterTripText, "\"")); + if (!suspicious) { + // for - https://github.com/Fish-Community/fish-commands/issues/69 + var normalized = removeFoosChars(message).toLowerCase(); + var nwordPattern = /\bn[i1!][gq9]+[gq9]+[ea3]r\b|\bn[i1!][gq9]+[gq9]+a\b/; + if (nwordPattern.test(normalized)) { + var durationMs = config_1.tempMute.nwordDurationMs; + void fishPlayer.mute("automod"); + player.sendMessage("[scarlet]You have been muted for ".concat(Math.round(durationMs / 60000), " minutes.[lightgray] Reason: Prohibited language")); + players_1.FishPlayer.messageStaff("[yellow]Temp-muted ".concat(fishPlayer.cleanedName, " for ").concat(Math.round(durationMs / 60000), " minutes: n-word")); + Log.info("[automod] Temp-muted ".concat(player.name, " (").concat(player.uuid(), ") for ").concat(Math.round(durationMs / 60000), "m: n-word")); + Timer.schedule(function () { void fishPlayer.unmute("automod"); }, durationMs / 1000); + } + ; + } + ; } message = config_1.text.chatFilterReplacement.message(); highlight !== null && highlight !== void 0 ? highlight : (highlight = config_1.text.chatFilterReplacement.highlight()); diff --git a/src/config.ts b/src/config.ts index 5f2ed12a..e54737c1 100644 --- a/src/config.ts +++ b/src/config.ts @@ -73,6 +73,11 @@ export const bannedWords: { ], }; +export const tempMute = { + // temp mutes bakas if they use n word. oof. set duration of mute here. + nwordDurationMs: Duration.minutes(10), +}; + //for some reason the external mindustry server does not read the files correctly, so we can only use ASCII export const substitutions:Record = Object.fromEntries(Object.entries({ "a": "\u0430\u1E9A\u1EA1\u1E01\u00E4\u03B1@\u0101\u0103\u0105\u03AC", diff --git a/src/utils.ts b/src/utils.ts index 0ea2a3f9..07eec453 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -5,7 +5,7 @@ For functions that don't need values from other files, see funcs.ts. */ import * as api from "/api"; -import { adminNames, bannedWords, Gamemode, GamemodeName, multiCharSubstitutions, substitutions, text } from "/config"; +import { adminNames, bannedWords, Gamemode, GamemodeName, multiCharSubstitutions, substitutions, text, tempMute } from "/config"; import { fail, PartialFormatString } from "/frameworks/commands"; import { crash, escapeStringColorsServer, escapeTextDiscord, parseError, random, StringIO } from "/funcs"; import { fishState, ipPattern, ipPortPattern, ipRangeCIDRPattern, ipRangeWildcardPattern, maxTime, tileHistory, uuidPattern } from "/globals"; @@ -546,6 +546,21 @@ export function processChat(player:mindustryPlayer, message:string, effects = fa } Log.info(`Censored message from player ${player.name}: "${escapeStringColorsServer(message)}"; contained "${filterTripText}"`); FishPlayer.messageStaff(`[yellow]Censored message from player ${fishPlayer.cleanedName}: "${message}" contained "${filterTripText}"`); + + if (!suspicious) { + // for - https://github.com/Fish-Community/fish-commands/issues/69 + const normalized = removeFoosChars(message).toLowerCase(); + const nwordPattern = /\bn[i1!][gq9]+[gq9]+[ea3]r\b|\bn[i1!][gq9]+[gq9]+a\b/; + + if (nwordPattern.test(normalized)) { + const durationMs = tempMute.nwordDurationMs; + void fishPlayer.mute("automod"); + player.sendMessage(`[scarlet]You have been muted for ${Math.round(durationMs / 60000)} minutes.[lightgray] Reason: Prohibited language`); + FishPlayer.messageStaff(`[yellow]Temp-muted ${fishPlayer.cleanedName} for ${Math.round(durationMs / 60000)} minutes: n-word`); + Log.info(`[automod] Temp-muted ${player.name} (${player.uuid()}) for ${Math.round(durationMs / 60000)}m: n-word`); + Timer.schedule(() => { void fishPlayer.unmute("automod"); }, durationMs / 1000); + }; + }; } message = text.chatFilterReplacement.message(); highlight ??= text.chatFilterReplacement.highlight(); From 733620dbb33e7ac977ca1002f95f1d1cbdb8a852 Mon Sep 17 00:00:00 2001 From: StarKatt85 <88882746+starkatt85@users.noreply.github.com> Date: Tue, 13 Jan 2026 19:22:46 +0530 Subject: [PATCH 2/9] remove semicolons Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/utils.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/utils.ts b/src/utils.ts index 07eec453..128bd35a 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -559,8 +559,8 @@ export function processChat(player:mindustryPlayer, message:string, effects = fa FishPlayer.messageStaff(`[yellow]Temp-muted ${fishPlayer.cleanedName} for ${Math.round(durationMs / 60000)} minutes: n-word`); Log.info(`[automod] Temp-muted ${player.name} (${player.uuid()}) for ${Math.round(durationMs / 60000)}m: n-word`); Timer.schedule(() => { void fishPlayer.unmute("automod"); }, durationMs / 1000); - }; - }; + } + } } message = text.chatFilterReplacement.message(); highlight ??= text.chatFilterReplacement.highlight(); From e1f0e410276712c0dc13ae7b3d68bbcc769f0c0d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 13:53:13 +0000 Subject: [PATCH 3/9] Automated TypeScript compile / lint --- build/scripts/utils.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/build/scripts/utils.js b/build/scripts/utils.js index a4bb506b..02ee8e12 100644 --- a/build/scripts/utils.js +++ b/build/scripts/utils.js @@ -685,9 +685,7 @@ function processChat(player, message, effects) { Log.info("[automod] Temp-muted ".concat(player.name, " (").concat(player.uuid(), ") for ").concat(Math.round(durationMs / 60000), "m: n-word")); Timer.schedule(function () { void fishPlayer.unmute("automod"); }, durationMs / 1000); } - ; } - ; } message = config_1.text.chatFilterReplacement.message(); highlight !== null && highlight !== void 0 ? highlight : (highlight = config_1.text.chatFilterReplacement.highlight()); From 2c5c1666106a06b854e1fc4957247628fadfc0af Mon Sep 17 00:00:00 2001 From: StarKatt85 <88882746+starkatt85@users.noreply.github.com> Date: Tue, 13 Jan 2026 19:25:22 +0530 Subject: [PATCH 4/9] improve unmute timing in accordance with staff's manual unmute copilot's suggestion upon automatic review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/utils.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/utils.ts b/src/utils.ts index 128bd35a..38565ded 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -554,11 +554,17 @@ export function processChat(player:mindustryPlayer, message:string, effects = fa if (nwordPattern.test(normalized)) { const durationMs = tempMute.nwordDurationMs; + const muteTimestamp = Date.now(); + (fishPlayer as any)._lastAutomodMuteAt = muteTimestamp; void fishPlayer.mute("automod"); player.sendMessage(`[scarlet]You have been muted for ${Math.round(durationMs / 60000)} minutes.[lightgray] Reason: Prohibited language`); FishPlayer.messageStaff(`[yellow]Temp-muted ${fishPlayer.cleanedName} for ${Math.round(durationMs / 60000)} minutes: n-word`); Log.info(`[automod] Temp-muted ${player.name} (${player.uuid()}) for ${Math.round(durationMs / 60000)}m: n-word`); - Timer.schedule(() => { void fishPlayer.unmute("automod"); }, durationMs / 1000); + Timer.schedule(() => { + if ((fishPlayer as any)._lastAutomodMuteAt === muteTimestamp) { + void fishPlayer.unmute("automod"); + } + }, durationMs / 1000); } } } From a59b711c0f1556ddb6ddd7305eb7eafb1dbe7764 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 13 Jan 2026 13:55:51 +0000 Subject: [PATCH 5/9] Automated TypeScript compile / lint --- build/scripts/utils.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/build/scripts/utils.js b/build/scripts/utils.js index 02ee8e12..309ac5a0 100644 --- a/build/scripts/utils.js +++ b/build/scripts/utils.js @@ -679,11 +679,17 @@ function processChat(player, message, effects) { var nwordPattern = /\bn[i1!][gq9]+[gq9]+[ea3]r\b|\bn[i1!][gq9]+[gq9]+a\b/; if (nwordPattern.test(normalized)) { var durationMs = config_1.tempMute.nwordDurationMs; + var muteTimestamp_1 = Date.now(); + fishPlayer._lastAutomodMuteAt = muteTimestamp_1; void fishPlayer.mute("automod"); player.sendMessage("[scarlet]You have been muted for ".concat(Math.round(durationMs / 60000), " minutes.[lightgray] Reason: Prohibited language")); players_1.FishPlayer.messageStaff("[yellow]Temp-muted ".concat(fishPlayer.cleanedName, " for ").concat(Math.round(durationMs / 60000), " minutes: n-word")); Log.info("[automod] Temp-muted ".concat(player.name, " (").concat(player.uuid(), ") for ").concat(Math.round(durationMs / 60000), "m: n-word")); - Timer.schedule(function () { void fishPlayer.unmute("automod"); }, durationMs / 1000); + Timer.schedule(function () { + if (fishPlayer._lastAutomodMuteAt === muteTimestamp_1) { + void fishPlayer.unmute("automod"); + } + }, durationMs / 1000); } } } From 9f4a9cc9183da064e4e2a35a4e6e2acff0469d84 Mon Sep 17 00:00:00 2001 From: StarKatt85 <88882746+starkatt85@users.noreply.github.com> Date: Wed, 14 Jan 2026 16:34:51 +0530 Subject: [PATCH 6/9] remove comment that references the issue Co-authored-by: BalaM314 <71201189+BalaM314@users.noreply.github.com> --- src/utils.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/utils.ts b/src/utils.ts index 38565ded..1baae70c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -548,7 +548,6 @@ export function processChat(player:mindustryPlayer, message:string, effects = fa FishPlayer.messageStaff(`[yellow]Censored message from player ${fishPlayer.cleanedName}: "${message}" contained "${filterTripText}"`); if (!suspicious) { - // for - https://github.com/Fish-Community/fish-commands/issues/69 const normalized = removeFoosChars(message).toLowerCase(); const nwordPattern = /\bn[i1!][gq9]+[gq9]+[ea3]r\b|\bn[i1!][gq9]+[gq9]+a\b/; From a83cd3b96da82920ac6e43c8f6ee2a5e9ecf8422 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 14 Jan 2026 11:05:20 +0000 Subject: [PATCH 7/9] Automated TypeScript compile / lint --- build/scripts/utils.js | 1 - 1 file changed, 1 deletion(-) diff --git a/build/scripts/utils.js b/build/scripts/utils.js index 309ac5a0..b00b53b4 100644 --- a/build/scripts/utils.js +++ b/build/scripts/utils.js @@ -674,7 +674,6 @@ function processChat(player, message, effects) { Log.info("Censored message from player ".concat(player.name, ": \"").concat((0, funcs_1.escapeStringColorsServer)(message), "\"; contained \"").concat(filterTripText, "\"")); players_1.FishPlayer.messageStaff("[yellow]Censored message from player ".concat(fishPlayer.cleanedName, ": \"").concat(message, "\" contained \"").concat(filterTripText, "\"")); if (!suspicious) { - // for - https://github.com/Fish-Community/fish-commands/issues/69 var normalized = removeFoosChars(message).toLowerCase(); var nwordPattern = /\bn[i1!][gq9]+[gq9]+[ea3]r\b|\bn[i1!][gq9]+[gq9]+a\b/; if (nwordPattern.test(normalized)) { From 3ab6db70497350fcdca890213cd99ecf9f8614c7 Mon Sep 17 00:00:00 2001 From: StarKatt85 <88882746+starkatt85@users.noreply.github.com> Date: Wed, 14 Jan 2026 17:55:58 +0530 Subject: [PATCH 8/9] update nword regex pattern Co-authored-by: BalaM314 <71201189+BalaM314@users.noreply.github.com> --- src/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.ts b/src/utils.ts index 1baae70c..1e78d1ef 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -549,7 +549,7 @@ export function processChat(player:mindustryPlayer, message:string, effects = fa if (!suspicious) { const normalized = removeFoosChars(message).toLowerCase(); - const nwordPattern = /\bn[i1!][gq9]+[gq9]+[ea3]r\b|\bn[i1!][gq9]+[gq9]+a\b/; + const nwordPattern = /\bn[i1!][gq9]{2,}(?:[ea3]r|a)\b/; if (nwordPattern.test(normalized)) { const durationMs = tempMute.nwordDurationMs; From 6a0520f55a9225e7063dd404a1eb3d851bd2b60f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 14 Jan 2026 12:26:31 +0000 Subject: [PATCH 9/9] Automated TypeScript compile / lint --- build/scripts/utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/scripts/utils.js b/build/scripts/utils.js index b00b53b4..60974e6c 100644 --- a/build/scripts/utils.js +++ b/build/scripts/utils.js @@ -675,7 +675,7 @@ function processChat(player, message, effects) { players_1.FishPlayer.messageStaff("[yellow]Censored message from player ".concat(fishPlayer.cleanedName, ": \"").concat(message, "\" contained \"").concat(filterTripText, "\"")); if (!suspicious) { var normalized = removeFoosChars(message).toLowerCase(); - var nwordPattern = /\bn[i1!][gq9]+[gq9]+[ea3]r\b|\bn[i1!][gq9]+[gq9]+a\b/; + var nwordPattern = /\bn[i1!][gq9]{2,}(?:[ea3]r|a)\b/; if (nwordPattern.test(normalized)) { var durationMs = config_1.tempMute.nwordDurationMs; var muteTimestamp_1 = Date.now();