C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using Oxide.Core;
using Oxide.Core.Plugins;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Chat Filter", "YourName", "1.0.0")]
[Description("Filters profanity and bad words from chat")]
internal class ChatFilter : RustPlugin
{
#region Configuration
private static ConfigData config;
private class ConfigData
{
public bool Enabled { get; set; } = true;
public string ReplaceChar { get; set; } = "*";
public ActionType Action { get; set; } = ActionType.Replace;
public int MuteDurationSeconds { get; set; } = 60;
public int KickWarningsCount { get; set; } = 3;
public List<string> BannedWords { get; set; }
public List<string> BannedPhrases { get; set; }
public List<string> IgnorePermissions { get; set; }
public ConfigData()
{
BannedWords = new List<string>
{
"fuck", "shit", "asshole", "bitch", "cunt", "dick", "pussy",
"хуй", "пизда", "бля", "еба", "залупа", "мудак", "гандон"
};
BannedPhrases = new List<string>();
IgnorePermissions = new List<string> { "chatfilter.ignore", "admin" };
}
}
public enum ActionType
{
Replace, // Заменить на звездочки
Mute, // Замутить на время
Kick, // Кикнуть с сервера
Warn // Только предупредить
}
protected override void LoadConfig()
{
base.LoadConfig();
config = Config.ReadObject<ConfigData>();
if (config == null)
{
LoadDefaultConfig();
}
}
protected override void LoadDefaultConfig()
{
config = new ConfigData();
PrintWarning("Default configuration created.Edit it in oxide/config/ChatFilter.json");
SaveConfig();
}
protected override void SaveConfig() => Config.WriteObject(config);
#endregion
#region Data Storage
private Dictionary<ulong, int> warningCounts;
private void LoadData()
{
warningCounts = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, int>>("ChatFilter_Warnings") ?? new Dictionary<ulong, int>();
}
private void SaveData()
{
Interface.Oxide.DataFileSystem.WriteObject("ChatFilter_Warnings", warningCounts);
}
#endregion
#region Hooks
private void Init()
{
LoadData();
permission.RegisterPermission("chatfilter.ignore", this);
permission.RegisterPermission("chatfilter.admin", this);
}
private void OnServerSave() => SaveData();
private void Unload() => SaveData();
private object OnPlayerChat(BasePlayer player, string message, ConVar.Chat.ChatChannel channel)
{
if (!config.Enabled) return null;
if (player == null) return null;
// Check ignore permissions
foreach (string perm in config.IgnorePermissions)
{
if (permission.UserHasPermission(player.UserIDString, perm))
{
return null; // Allow message
}
}
string originalMessage = message;
string lowerMessage = message.ToLower();
bool isOffensive = false;
string matchedWord = "";
// Check banned words
foreach (string word in config.BannedWords)
{
if (lowerMessage.Contains(word.ToLower()))
{
isOffensive = true;
matchedWord = word;
break;
}
}
// Check banned phrases
if (!isOffensive)
{
foreach (string phrase in config.BannedPhrases)
{
if (lowerMessage.Contains(phrase.ToLower()))
{
isOffensive = true;
matchedWord = phrase;
break;
}
}
}
if (!isOffensive) return null;
// Handle offense
LogOffense(player, originalMessage, matchedWord);
switch (config.Action)
{
case ActionType.Replace:
string filtered = FilterMessage(message);
SendReply(player, $"<color=orange>Your message was filtered: {filtered}</color>");
return filtered;
case ActionType.Mute:
MutePlayer(player);
SendReply(player, $"<color=red>You have been muted for {config.MuteDurationSeconds} seconds for offensive language!</color>");
return true; // Block message
case ActionType.Kick:
KickPlayer(player, matchedWord);
return true;
case ActionType.Warn:
int warnings = WarnPlayer(player);
SendReply(player, $"<color=orange>Warning {warnings}/{config.KickWarningsCount}! Please do not use offensive language.</color>");
return true; // Block message
default:
return null;
}
}
#endregion
#region Core Logic
private string FilterMessage(string message)
{
string filtered = message;
foreach (string word in config.BannedWords)
{
string pattern = $@"(?i)\b{Regex.Escape(word)}\b";
string replacement = new string(config.ReplaceChar[0], word.Length);
filtered = Regex.Replace(filtered, pattern, replacement, RegexOptions.IgnoreCase);
}
foreach (string phrase in config.BannedPhrases)
{
string pattern = $@"(?i){Regex.Escape(phrase)}";
string replacement = new string(config.ReplaceChar[0], phrase.Length);
filtered = Regex.Replace(filtered, pattern, replacement, RegexOptions.IgnoreCase);
}
return filtered;
}
private void MutePlayer(BasePlayer player)
{
// Simple mute using temporary permission
string mutePerm = "chatfilter.muted";
if (!permission.PermissionExists(mutePerm))
{
permission.RegisterPermission(mutePerm, this);
}
permission.GrantUserPermission(player.UserIDString, mutePerm);
timer.Once(config.MuteDurationSeconds, () =>
{
if (player != null && player.IsConnected)
{
permission.RevokeUserPermission(player.UserIDString, mutePerm);
SendReply(player, "<color=green>Your mute has expired.Please follow the chat rules!</color>");
}
});
}
private void KickPlayer(BasePlayer player, string reason)
{
string kickReason = $"Kicked for offensive language: '{reason}'";
player.Kick(kickReason);
Puts($"Kicked {player.displayName} ({player.userID}) for: {reason}");
}
private int WarnPlayer(BasePlayer player)
{
ulong userId = player.userID;
if (!warningCounts.ContainsKey(userId))
{
warningCounts[userId] = 0;
}
warningCounts[userId]++;
if (warningCounts[userId] >= config.KickWarningsCount)
{
KickPlayer(player, $"exceeded {config.KickWarningsCount} warnings");
warningCounts.Remove(userId);
}
SaveData();
return warningCounts[userId];
}
private void LogOffense(BasePlayer player, string message, string matched)
{
Puts($"[CHAT FILTER] {player.displayName} ({player.userID}): '{message}' | Matched: '{matched}'");
// Optional: log to file
string logLine = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} | {player.displayName} | {player.userID} | {message} | {matched}";
LogToFile("offenses", logLine, this);
}
[ConsoleCommand("chatfilter.reload")]
private void cmdReload(ConsoleSystem.Arg args)
{
if (args.Connection != null && !permission.UserHasPermission(args.Connection.UserId.ToString(), "chatfilter.admin"))
{
args.ReplyWith("No permission");
return;
}
LoadConfig();
LoadData();
args.ReplyWith("ChatFilter reloaded");
Puts("ChatFilter configuration reloaded");
}
[ChatCommand("resetwarns")]
private void cmdResetWarns(BasePlayer player, string command, string[] args)
{
if (!permission.UserHasPermission(player.UserIDString, "chatfilter.admin"))
{
SendReply(player, "No permission");
return;
}
if (args.Length == 0)
{
SendReply(player, "Usage: /resetwarns <steamID> or 'all'");
return;
}
if (args[0].ToLower() == "all")
{
warningCounts.Clear();
SaveData();
SendReply(player, "Reset all warnings");
return;
}
if (ulong.TryParse(args[0], out ulong steamId))
{
if (warningCounts.Remove(steamId))
{
SaveData();
SendReply(player, $"Reset warnings for {steamId}");
}
else
{
SendReply(player, "No warnings found for that player");
}
}
}
#endregion
}
}