C#:
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Libraries;
using Oxide.Core.Plugins;
using System.Text.RegularExpressions;
using CompanionServer;
using Oxide.Core.Libraries.Covalence;
using UnityEngine;
using ConVar;
using Facepunch.Math;
namespace Oxide.Plugins {
[Info("ChatPlus", "RustPlugin.ru - Developed by Vlad-00003", "1.5.5", ResourceId = 82)]
public class ChatPlus : CovalencePlugin {
#region Global vars
private ChatConfig config;
private static ChatPlus m_Instance;
private static Dictionary<string, MuteData> mutes = new Dictionary<string, MuteData>();
private Dictionary<string, PlayerData> PlayersData = new Dictionary<string, PlayerData>();
private PlayerData defaultData = new PlayerData();
private bool GlobalMute = false;
private bool HasExpired;
private IPlayer ConsoleIPly;
DynamicConfigFile mutes_File = Interface.Oxide.DataFileSystem.GetFile("ChatPlus_Mutes");
DynamicConfigFile players_File = Interface.Oxide.DataFileSystem.GetFile("ChatPlus_Players");
public static Dictionary<Plugin, Func<IPlayer, string>> ThirdPartyTitles = new Dictionary<Plugin, Func<IPlayer, string>>();
#endregion
#region Initialization and quiting
void OnServerInitialized() {
m_Instance = this;
LoadMessages();
LoadConfig();
LoadData();
config.RegisterPerms();
timer.Repeat(10, 0, () => {
List<string> expired = mutes.Where(m => m.Value.Expired).Select(m => m.Key).ToList();
foreach (string userID in expired) {
IPlayer player = players.FindPlayerById(userID.ToString());
if (player == null) continue;
mutes.Remove(userID);
BroadcastChat("MUTE.EXPIRED", player.Name);
Log(LogType.Mute, string.Format(GetMsg("MUTE.EXPIRED"), player.Name));
if (!HasExpired) HasExpired = true;
}
if (HasExpired) {
SaveMutes();
HasExpired = false;
}
}
);
}
void Unload() {
OnServerSave();
}
void OnServerSave() {
SaveMutes();
players_File.WriteObject(PlayersData.Where(p => !p.Value.Equals(defaultData)).ToDictionary(p => p.Key, p => p.Value));
}
private void SaveMutes() {
mutes_File.WriteObject(mutes);
}
void LoadData() {
mutes = mutes_File.ReadObject<Dictionary<string, MuteData>>();
PlayersData = players_File.ReadObject<Dictionary<string, PlayerData>>();
}
#endregion
private void PrintToChatMessageFake(string name, string userID, string message) {
var prefix = config.Get(config.prefixes, "chatplus.default").Format;
var nameColor = config.Get(config.names, "chatplus.default").Format;
var messageColor = config.Get(config.messages, "chatplus.default").Format;
name = string.Format(nameColor, RemoveTags(name));
if (prefix.Length > 0) name = $"{prefix} {name}";
message = RemoveTags(message);
message = string.Format(messageColor, message);
SendChat(name, message, "", userID);
}
private object OnPlayerOfflineChat(ulong playerId, string playerName, string message, Chat.ChatChannel channel) {
if (GlobalMute) {
return false;
}
var userId = playerId.ToString();
var pData = GetPlayerData(userId, playerName);
if (SpamCheck(message) != null) return false;
if (MuteData.IsMuted(userId)) return false;
if (config.CapsBlock) {
message = RemoveCaps(message);
}
message = RemoveTags(message);
bool mute;
var censorMessage = CensorBadWords(message, out mute);
if (config.BadWordsBlock & mute) {
Mute(userId, playerName, new TimeSpan(0, 0, config.MuteBadWordsDefault), config.MuteReasonAutoMute);
}
var prefix = config.Get(config.prefixes, pData.Prefix).Format;
var nameColor = config.Get(config.names, pData.NameColor).Format;
var messageColor = config.Get(config.messages, pData.MessageColor).Format;
var name = string.Format(nameColor, RemoveTags(playerName));
message = string.Format(messageColor, message);
censorMessage = string.Format(messageColor, censorMessage);
if (prefix.Length > 0) name = $"{prefix} {name}";
if (channel != Chat.ChatChannel.Team) {
SendChat(name, message, censorMessage, userId);
Log(LogType.Chat, $"{name}[{userId}]: {message}");
}
else {
var playerTeam = RelationshipManager.ServerInstance.FindPlayersTeam(playerId);
if (playerTeam == null) return false;
var onlineMembers = playerTeam.GetOnlineMemberConnections();
if (onlineMembers != null) SendChat(name, message, censorMessage, userId, onlineMembers.Select(x => x.player as BasePlayer));
playerTeam.BroadcastTeamChat(playerId, Formatter.ToPlaintext(name), Formatter.ToPlaintext(message), "#fff");
Log(LogType.TeamChat, $"{name}[{userId}]: {message}");
}
Chat.Record(new Chat.ChatEntry {
Channel = channel, Message = Formatter.ToPlaintext(message), UserId = userId, Username = Formatter.ToPlaintext(name), Color = "#5af", Time = Epoch.Current
}
);
ServerConsole.PrintColoured(ConsoleColor.DarkYellow, $"[{channel}] {Formatter.ToPlaintext(name)}({userId}) : ", ConsoleColor.DarkGreen, Formatter.ToPlaintext(message));
return true;
}
object OnPlayerChat(BasePlayer player, string message, Chat.ChatChannel channel) {
var sender = player.IPlayer;
if (GlobalMute) {
if (!CanMuteAll(sender)) {
Reply(sender, "MUTE.ALL.DISABLED");
return false;
}
}
var pData = GetPlayerData(sender);
if (pData.IsAdmin && channel != Chat.ChatChannel.Team) {
Log(LogType.Chat, $"[ADMIN MODE] {sender.Name}({sender.Id}): {message}");
bool outer;
var cens = CensorBadWords(message, out outer);
cens = string.Format(config.adminPrivilages.AdminFormat, cens);
message = string.Format(config.adminPrivilages.AdminFormat, message);
SendChat("", message, cens);
return false;
}
if (pData.IsModer) {
Log(LogType.Chat, $"[MODERATOR MODE] {sender.Name}({sender.Id}): {message}");
bool outer;
var cens = CensorBadWords(message, out outer);
cens = string.Format(config.adminPrivilages.ModerFormat, cens);
message = string.Format(config.adminPrivilages.ModerFormat, message);
SendChat("", message, cens);
return false;
}
if (SpamCheck(sender, message) != null) return false;
if (MuteCheck(sender) != null) {
//TODO find a way to make DiscordMesssages die
return false;
}
if (config.CapsBlock) {
message = RemoveCaps(message);
}
message = RemoveTags(message);
bool mute;
var censorMessage = CensorBadWords(message, out mute);
if (config.BadWordsBlock & mute) {
Mute(sender, new TimeSpan(0, 0, config.MuteBadWordsDefault), config.MuteReasonAutoMute, sender);
}
var prefix = config.Get(config.prefixes, pData.Prefix).Format;
var nameColor = config.Get(config.names, pData.NameColor).Format;
var messageColor = config.Get(config.messages, pData.MessageColor).Format;
var name = string.Format(nameColor, RemoveTags(sender.Name));
message = string.Format(messageColor, message);
censorMessage = string.Format(messageColor, censorMessage);
foreach (var thirdPartyTitle in ThirdPartyTitles) {
try {
string title = thirdPartyTitle.Value(sender);
if (!string.IsNullOrEmpty(title)) {
prefix = title + " " + prefix;
}
}
catch (Exception ex) {
PrintError($"Error when trying to get third-party title from plugin '{thirdPartyTitle.Key.Title}'{Environment.NewLine}{ex}");
}
}
Dictionary<string, object> hookDictionary = new Dictionary<string, object>() {
["Player"]
= sender, ["Message"] = message, ["CensoredMessage"] = censorMessage, ["Prefixes"] = prefix
}
;
foreach (var plugin in plugins.GetAll()) {
object result = plugin.CallHook("OnChatPlusMessage", hookDictionary);
var dict = result as Dictionary<string, object>;
if (dict != null) {
try {
sender = dict["Player"] as IPlayer;
message = dict["Message"] as string;
censorMessage = dict["CensoredMessage"] as string;
prefix = dict["Prefixes"] as string;
}
catch (Exception ex) {
PrintWarning($"Plugin '{plugin.Title}({plugin.Version})' failed to modify the ChatPlus message data.Error:\n{ex.Message}");
}
}
else if (result != null) return null;
}
if (prefix.Length > 0) name = $"{prefix} {name}";
if (channel != Chat.ChatChannel.Team) {
SendChat(name, message, censorMessage, sender.Id);
Log(LogType.Chat, $"{name}[{sender.Id}]: {message}");
}
else {
var playerTeam = RelationshipManager.ServerInstance.FindPlayersTeam(player.userID);
if (playerTeam == null) return false;
var onlineMembers = playerTeam.GetOnlineMemberConnections();
if (onlineMembers != null) SendChat(name, message, censorMessage, sender.Id, onlineMembers.Select(x => x.player as BasePlayer));
playerTeam.BroadcastTeamChat(player.userID, Formatter.ToPlaintext(name), Formatter.ToPlaintext(message), "#fff");
Log(LogType.TeamChat, $"{name}[{sender.Id}]: {message}");
}
Chat.Record(new Chat.ChatEntry {
Channel = channel, Message = Formatter.ToPlaintext(message), UserId = sender.Id, Username = Formatter.ToPlaintext(name), Color = "#5af", Time = Epoch.Current
}
);
ServerConsole.PrintColoured(ConsoleColor.DarkYellow, $"[{channel}] {Formatter.ToPlaintext(name)}({sender.Id}) : ", ConsoleColor.DarkGreen, Formatter.ToPlaintext(message));
return true;
}
#region Chat handling
private string RemoveTags(string message) {
//List<string> forbiddenTags = new List<string>{
// "</color>",
// "</size>",
// "<b>",
// "</b>",
// "<i>",
// "</i>"
//};
//message = Regex.Replace(message, "(<color=.+?>)", string.Empty, RegexOptions.IgnoreCase);
//message = Regex.Replace(message, "(<size=.+?>)", string.Empty, RegexOptions.IgnoreCase);
//foreach (string tag in forbiddenTags)
// message = Regex.Replace(message, tag, string.Empty, RegexOptions.IgnoreCase);
return Formatter.ToPlaintext(message).EscapeRichText();
}
string RemoveCaps(string message) {
var ss = message.Split(' ');
for (int j = 0; j < ss.Length; j++) for (int i = 1; i < ss[j].Length; i++) {
var sym = ss[j][i];
if (char.IsLower(sym)) continue;
ss[j] = ss[j].Remove(i, 1);
ss[j] = ss[j].Insert(i, char.ToLower(sym).ToString());
}
return string.Join(" ", ss);
}
bool? MuteCheck(IPlayer sender) {
if (MuteData.IsMuted(sender.Id)) {
MuteData md = mutes[sender.Id];
Reply(sender, "YOU.MUTED", md.Initiator, md.Reason, md.Remain);
return true;
}
return null;
}
bool? SpamCheck(IPlayer sender, string message) {
if (message.Length > 500) {
sender.Kick(GetMsg("CHAT.TOOMUCH", sender));
return false;
}
if (message.Length > 100) {
Reply(sender, "CHAT.SPAM");
return false;
}
return null;
}
bool? SpamCheck(string message) {
if (message.Length > 100) return false;
return null;
}
public string CensorBadWords(string input, out bool found) {
found = false;
string temp = input.ToLower();
foreach (var swear in config.badWords) {
var firstIndex = temp.IndexOf(swear.Key, StringComparison.Ordinal);
if (firstIndex >= 0 && swear.Value.All(exception => temp.IndexOf(exception, StringComparison.Ordinal) < 0)) {
while (firstIndex < input.Length && input[firstIndex] != ' ') {
input = input.Remove(firstIndex, 1);
input = input.Insert(firstIndex, "*");
firstIndex++;
found = true;
}
}
}
return input;
}
#endregion
#region Logging
enum LogType {
Chat, TeamChat, Mute, Pm, ServerConsole
}
private void Log(LogType type, string msg) {
var text = Formatter.ToPlaintext(msg);
switch (type) {
case LogType.Chat : Interface.Oxide.RootLogger.Write(Core.Logging.LogType.Info, $"[CHAT] {text}");
return;
case LogType.Mute : Interface.Oxide.RootLogger.Write(Core.Logging.LogType.Info, $"[MUTE] {text}");
return;
case LogType.Pm : Interface.Oxide.RootLogger.Write(Core.Logging.LogType.Info, $"[PM] {text}");
return;
case LogType.ServerConsole : Interface.Oxide.RootLogger.Write(Core.Logging.LogType.Info, $"[ServerConsole] {text}");
return;
case LogType.TeamChat : Interface.Oxide.RootLogger.Write(Core.Logging.LogType.Info, $"[TEAM CHAT] {text}");
return;
}
}
#endregion
#region Broadcasting
void SendChat(string name, string message, string censorMessage = "", string userId = "0", IEnumerable<BasePlayer> receivers = null) {
name = covalence.FormatText(name);
message = covalence.FormatText(message);
censorMessage = covalence.FormatText(censorMessage);
if (string.IsNullOrEmpty(censorMessage)) censorMessage = message;
var channel = receivers == null ? 0 : 1;
receivers = receivers ?? BasePlayer.activePlayerList;
foreach (var player in receivers) {
var msg = GetPlayerData(player).Censor ? censorMessage : message;
player?.SendConsoleCommand("chat.add", channel, userId, string.IsNullOrEmpty(name) ? $"{msg}" : $"{name}: {msg}");
}
}
void BroadcastChat(string langKey, params object[] args) {
foreach (var player in BasePlayer.activePlayerList) {
player.ChatMessage(covalence.FormatText(string.Format(GetMsg(langKey, player), args)));
}
}
private void Reply(IPlayer player, string langkey, params object[] args) {
if (player == null) return;
var message = string.Format(GetMsg(langkey, player), args);
message = player.IsServer ? Formatter.ToPlaintext(message) : covalence.FormatText(message);
if (player.IsServer | player.IsConnected) player.Reply(message);
}
#endregion
#region Sub functions
void Mute(string targetId, string targetName, TimeSpan? time, string reason) {
if (string.IsNullOrEmpty(reason)) reason = config.MuteReason;
string sender = "ChatPlus";
string log;
if (!time.HasValue) {
mutes[targetId] = new MuteData(sender, reason);
BroadcastChat("USER.MUTED.REASON", sender, targetName, reason, "Unlimited");
log = string.Format(GetMsg("USER.MUTED.LOG"), sender, targetName, "Unlimited", reason);
Interface.CallHook("OnBetterChatMuted", targetName, null, reason);
}
else {
mutes[targetId] = new MuteData(sender, reason, time.Value);
BroadcastChat("USER.MUTED.REASON", sender, targetName, reason, MuteData.TimeToString(time.Value));
log = string.Format(GetMsg("USER.MUTED.LOG"), sender, targetName, MuteData.TimeToString(time.Value), reason);
Interface.CallHook("OnBetterChatTimeMuted", targetName, null, time.Value, reason);
}
Log(LogType.Mute, log);
SaveMutes();
}
void Mute(IPlayer target, TimeSpan? time, string reason, IPlayer player) {
if (string.IsNullOrEmpty(reason)) reason = config.MuteReason;
string sender = target == player ? "ChatPlus" : player.IsServer ? config.ConsoleName : player.Name;
if (config.adminPrivilages.HideAdmins.HasValue && config.adminPrivilages.HideAdmins.Value && !player.IsServer) sender = config.adminPrivilages.AdminReplace;
string log;
if (!time.HasValue) {
mutes[target.Id] = new MuteData(sender, reason);
BroadcastChat("USER.MUTED.REASON", sender, target.Name, reason, "Unlimited");
log = string.Format(GetMsg("USER.MUTED.LOG"), sender, target.Name, "Unlimited", reason);
Interface.CallHook("OnBetterChatMuted", target, player, reason);
}
else {
mutes[target.Id] = new MuteData(sender, reason, time.Value);
BroadcastChat("USER.MUTED.REASON", sender, target.Name, reason, MuteData.TimeToString(time.Value));
log = string.Format(GetMsg("USER.MUTED.LOG"), sender, target.Name, MuteData.TimeToString(time.Value), reason);
Interface.CallHook("OnBetterChatTimeMuted", target, player, time.Value, reason);
}
Log(LogType.Mute, log);
SaveMutes();
}
private List<IPlayer> GetPlayers(string NameOrID) {
return players.FindPlayers(NameOrID).ToList();
}
private void SendChatHelp(IPlayer player) {
string msg = GetMsg("CMD.CHAT.HELP", player);
if (CanMuteAll(player)) msg += GetMsg("CMD.MUTE.ALL.HELP", player);
if (IsAdmin(player)) msg += GetMsg("CMD.CHAT.HELP.PERMISSION.ADMIN", player);
if (IsModerator(player)) msg += GetMsg("CMD.CHAT.HELP.PERMISSION.MODERATOR", player);
msg = player.IsServer ? Formatter.ToPlaintext(msg) : covalence.FormatText(msg);
player.Message(msg);
}
#endregion
#region Flags
bool IsModerator(IPlayer player) => PermissionService.HasPermission(player.Id, config.adminPrivilages.ModerPermiss) || player.IsAdmin;
//player.net.connection.authLevel >= 1;
bool IsAdmin(IPlayer player) => PermissionService.HasPermission(player.Id, config.adminPrivilages.AdminPermiss) || player.IsAdmin;
//player.net.connection.authLevel >= 2;
bool CanMute(IPlayer player) => PermissionService.HasPermission(player.Id, config.adminPrivilages.MutePermiss) || player.IsAdmin;
//player.net.connection.authLevel >= 1;
bool CanMuteAll(IPlayer player) => PermissionService.HasPermission(player.Id, config.adminPrivilages.MuteAllPermiss) || player.IsAdmin;
//player.net.connection.authLevel >= 2;
bool CanAssign(IPlayer player) => PermissionService.HasPermission(player.Id, config.adminPrivilages.AssignPermiss) || player.IsAdmin;
//player.net.connection.authLevel >= 2;
bool CanUnMute(IPlayer player) => PermissionService.HasPermission(player.Id, config.adminPrivilages.UnMutePermiss) || player.IsAdmin;
//player.net.connection.authLevel >= 1;
#endregion
#region Commands
object OnServerCommand(ConsoleSystem.Arg arg) {
if (arg?.cmd?.FullName != null && arg?.cmd?.FullName == "global.say") {
if (!arg.HasArgs()) return false;
string message = string.Join(" ", arg.Args);
bool outer;
var cens = CensorBadWords(message, out outer);
cens = string.Format(config.ConsoleFormat, config.ConsoleName, cens);
message = string.Format(config.ConsoleFormat, config.ConsoleName, message);
Log(LogType.ServerConsole, message);
SendChat("", message, cens);
return true;
}
else return null;
}
[Command("chatplus.prefix")]
private void cmdConsolePrefix(IPlayer player, string cmd, string[] Args) {
if (!CanAssign(player)) {
Reply(player, "NO.ACCESS");
return;
}
if (Args == null || Args.Length < 2) {
Reply(player, "CMD.HELP.PREFIX");
return;
}
var recivers = GetPlayers(Args[0]);
if (recivers == null || recivers.Count == 0) {
Reply(player, "PLAYER.NOT.FOUND", Args[0]);
return;
}
if (recivers.Count > 1) {
Reply(player, "MULTIPLE.PLAYERS.FOUND", string.Join("\n", recivers.Select(p => $"{p.Name} ({p.Id})").ToArray()));
return;
}
var target = recivers.First();
var pdata = GetPlayerData(target);
if (!PermissionService.HasPermission(target.Id, Args[1])) {
Reply(player, "NO.PERMISSION.PLAYER");
return;
}
pdata.Prefix = Args[1];
Reply(player, "PREFIX.CHANGED", Args[1]);
}
[Command("chatplus.name")]
private void cmdConsoleName(IPlayer player, string cmd, string[] Args) {
if (!CanAssign(player)) {
Reply(player, "NO.ACCESS");
return;
}
if (Args == null || Args.Length < 2) {
Reply(player, "CMD.HELP.NAME");
return;
}
var recivers = GetPlayers(Args[0]);
if (recivers == null || recivers.Count == 0) {
Reply(player, "PLAYER.NOT.FOUND", Args[0]);
return;
}
if (recivers.Count > 1) {
Reply(player, "MULTIPLE.PLAYERS.FOUND", string.Join("\n", recivers.Select(p => $"{p.Name} ({p.Id})").ToArray()));
return;
}
var target = recivers.First();
var pdata = GetPlayerData(target);
if (!PermissionService.HasPermission(target.Id, Args[1])) {
Reply(player, "NO.PERMISSION.PLAYER");
return;
}
pdata.NameColor = Args[1];
Reply(player, "NAME.COLOR.CHANGED", Args[1]);
}
[Command("chatplus.message")]
private void cmdConsoleMessage(IPlayer player, string cmd, string[] Args) {
if (!CanAssign(player)) {
Reply(player, "NO.ACCESS");
return;
}
if (Args == null || Args.Length < 2) {
Reply(player, "CMD.HELP.MESSAGE");
return;
}
var recivers = GetPlayers(Args[0]);
if (recivers == null || recivers.Count == 0) {
Reply(player, "PLAYER.NOT.FOUND", Args[0]);
return;
}
if (recivers.Count > 1) {
Reply(player, "MULTIPLE.PLAYERS.FOUND", string.Join("\n", recivers.Select(p => $"{p.Name} ({p.Id})").ToArray()));
return;
}
var target = recivers.First();
var pdata = GetPlayerData(target);
if (!PermissionService.HasPermission(target.Id, Args[1])) {
Reply(player, "NO.PERMISSIO.PLAYERN");
return;
}
pdata.MessageColor = Args[1];
Reply(player, "MESSAGE.COLOR.CHANGED", Args[1]);
}
[Command("muteall")]
private void cmdChatMuteAll(IPlayer player, string cmd, string[] Args) {
if (!CanMuteAll(player)) {
Reply(player, "NO.ACCESS");
return;
}
if (GlobalMute) {
BroadcastChat("MUTE.ALL.ENABLED");
GlobalMute = false;
return;
}
BroadcastChat("MUTE.ALL.DISABLED");
GlobalMute = true;
return;
}
[Command("mutelist")]
void cmdChatMuteList(IPlayer player, string cmd, string[] Args) {
if (!CanMute(player) || !CanUnMute(player)) {
Reply(player, "NO.ACCESS");
return;
}
string msg;
if (mutes.Count == 0) msg = GetMsg("MUTE.LIST.NOONE");
else {
msg = GetMsg("MUTE.LIST.HEAD");
foreach (var mute in mutes) {
msg += "\n" + string.Format(GetMsg("MUTE.LIST.BODY", player), mute.Value.Initiator, $"{players.FindPlayerById(mute.Key.ToString()).Name} ({mute.Key})", mute.Value.Reason, mute.Value.Remain);
}
}
player.Reply(msg);
}
[Command("mute")]
void cmdChatMute(IPlayer player, string cmd, string[] args) {
if (!CanMute(player)) {
Reply(player, "NO.ACCESS");
return;
}
if (args.Length < 1) {
Reply(player, "CMD.MUTE.HELP");
return;
}
var recivers = GetPlayers(args[0]);
if (recivers == null || recivers.Count == 0) {
Reply(player, "PLAYER.NOT.FOUND", args[0]);
return;
}
if (recivers.Count > 1) {
Reply(player, "MULTIPLE.PLAYERS.FOUND", string.Join("\n", recivers.Select(p => $"{p.Name} ({p.Id})").ToArray()));
return;
}
var mutePlayer = recivers.First();
if (MuteData.IsMuted(mutePlayer.Id)) {
Reply(player, "USER.ALREADY.MUTED", mutePlayer.Name, mutes[mutePlayer.Id].Reason, mutes[mutePlayer.Id].Remain);
return;
}
TimeSpan time;
if (args.Length == 1) {
Mute(mutePlayer, null, null, player);
return;
}
if (MuteData.StringToTime(args[1], out time)) {
Mute(mutePlayer, time, string.Join(" ", args.Skip(2).ToArray()), player);
return;
}
Mute(mutePlayer, null, string.Join(" ", args.Skip(1).ToArray()), player);
}
[Command("unmute")]
void cmdChatUnMute(IPlayer player, string cmd, string[] args) {
if (!CanUnMute(player)) {
Reply(player, "NO.ACCESS");
return;
}
if (args.Length == 0) {
Reply(player, "CMD.UNMUTE.HELP");
return;
}
var recivers = GetPlayers(args[0]);
if (recivers == null || recivers.Count == 0) {
Reply(player, "PLAYER.NOT.FOUND", args[0]);
return;
}
recivers = recivers.Where(p => mutes.ContainsKey(p.Id)).ToList();
if (recivers.Count == 0) {
Reply(player, "PLAYER.NOT.MUTED");
return;
}
if (recivers.Count > 1) {
Reply(player, "MULTIPLE.PLAYERS.FOUND", string.Join("\n", recivers.Select(p => $"{p.Name} ({p.Id})").ToArray()));
return;
}
var mutePlayer = recivers.First();
mutes.Remove(mutePlayer.Id);
BroadcastChat("USER.UNMUTED", player.Name, mutePlayer.Name);
string log = GetMsg("USER.UNMUTED.LOG");
log = string.Format(log, player.Name, mutePlayer.Name);
Log(LogType.Mute, log);
SaveMutes();
}
[Command("chat")]
void cmdChat(IPlayer player, string cmd, string[] args) {
if (args.Length == 0) {
SendChatHelp(player);
return;
}
var playerData = GetPlayerData(player);
switch (args[0]) {
case "reset" : PlayersData[player.Id] = new PlayerData();
Reply(player, "RESET.SUCCESSFULL");
return;
case "admin" : if (!IsAdmin(player)) {
Reply(player, "NO.ACCESS");
return;
}
if (playerData.IsAdmin) {
playerData.IsAdmin = false;
Reply(player, "ADMIN.DISABLE");
return;
}
playerData.IsAdmin = true;
Reply(player, "ADMIN.ENABLE");
return;
case "moder" : if (!IsModerator(player)) {
Reply(player, "NO.ACCESS");
return;
}
if (playerData.IsModer) {
playerData.IsModer = false;
Reply(player, "MODERATOR.DISABLE");
return;
}
playerData.IsModer = true;
Reply(player, "MODERATOR.ENABLE");
return;
case "censor" : if (playerData.Censor) {
playerData.Censor = false;
Reply(player, "CENSOR.DISABLED");
return;
}
playerData.Censor = true;
Reply(player, "CENSOR.ENABLED");
return;
case "ignore" : if (args.Length == 2 && args[1] == "list") {
if (playerData.BlackList.Count == 0) {
Reply(player, "IGNORE.LIST.IS.EMPTY");
return;
}
Reply(player, "IGNORE.LIST", string.Join(", ", playerData.BlackList.Select(p => GetPlayerData(p).Name).ToArray()));
return;
}
if (args.Length < 3 || (args[1] != "add" && args[1] != "remove")) {
Reply(player, "CMD.CHAT.IGNORE.HELP");
return;
}
bool mode = args[1] == "add";
var reply = 0;
var recivers = players.FindPlayers(args[2]).ToList();
if (!recivers.Any()) {
Reply(player, "PLAYER.NOT.FOUND", args[2]);
return;
}
if (recivers.Count > 1) {
Reply(player, "MULTIPLE.PLAYERS.FOUND", string.Join("\n", recivers.Select(p => $"{p.Name} ({p.Id})").ToArray()));
return;
}
var ignorePlayer = recivers.First();
if (mode) {
if (!playerData.BlackList.Contains(ignorePlayer.Id)) {
playerData.BlackList.Add(ignorePlayer.Id);
Reply(player, "USER.ADD.IGNORE.LIST", ignorePlayer.Name);
if (ignorePlayer.IsConnected) Reply(ignorePlayer, "YOU.ADD.IGNORE.LIST", player.Name);
return;
}
Reply(player, "USER.IS.IGNORE.LIST", ignorePlayer.Name);
return;
}
else {
if (playerData.BlackList.Contains(ignorePlayer.Id)) {
playerData.BlackList.Remove(ignorePlayer.Id);
Reply(player, "USER.REMOVE.IGNORE.LIST", ignorePlayer.Name);
Reply(ignorePlayer, "YOU.REMOVE.IGNORE.LIST", player.Name);
return;
}
Reply(player, "NOT.ON.IGNORE.LIST", ignorePlayer.Name);
return;
}
case "sound" : if (args.Length == 1 || (args[1] != "on" && args[1] != "off")) {
Reply(player, "CMD.CHAT.SOUND.HELP");
return;
}
bool pmSound = args[1] == "on";
playerData.PMSound = pmSound;
if (pmSound) {
Reply(player, "SOUND.ENABLED");
return;
}
else {
Reply(player, "SOUND.DISABLED");
return;
}
case "prefix" : var aviablePrefixes = config.prefixes.Where(p => PermissionService.HasPermission(player.Id, p.Perm) && playerData.Prefix != p.Perm || p.Perm == "chatplus.default" && playerData.Prefix != p.Perm).ToList();
if (aviablePrefixes.Count == 0) {
Reply(player, "NO.AVAILABLE.PREFIXS");
return;
}
if (args.Length == 1) {
Reply(player, "AVAILABLE.COLORS.PREFIX", string.Join(", ", aviablePrefixes.Select(p => $"{p.Arg}({covalence.FormatText(p.Format)})").ToArray()));
return;
}
var selectedPrefix = aviablePrefixes.FirstOrDefault(p => p.Arg == args[1]);
if (selectedPrefix == null) {
Reply(player, "PREFIX.NOT.FOUND", args[1]);
return;
}
playerData.Prefix = selectedPrefix.Perm;
Reply(player, "PREFIX.CHANGED", selectedPrefix.Arg);
return;
case "name" : var aviableNameColors = config.names.Where(p => PermissionService.HasPermission(player.Id, p.Perm) && playerData.NameColor != p.Perm || p.Perm == "chatplus.default" && playerData.NameColor != p.Perm).ToList();
if (aviableNameColors.Count == 0) {
Reply(player, "NO.AVAILABLE.COLORS");
return;
}
if (args.Length == 1) {
Reply(player, "AVAILABLE.COLORS.NAME", string.Join(", ", aviableNameColors.Select(p => covalence.FormatText(string.Format(p.Format, p.Arg))).ToArray()));
return;
}
var selectedNameColor = aviableNameColors.FirstOrDefault(p => p.Arg == args[1]);
if (selectedNameColor == null) {
Reply(player, "COLOR.NOT.FOUND", args[1]);
return;
}
playerData.NameColor = selectedNameColor.Perm;
Reply(player, "NAME.COLOR.CHANGED", selectedNameColor.Arg);
return;
case "message" : var aviableMessageColors = config.messages.Where(p => PermissionService.HasPermission(player.Id, p.Perm) && playerData.MessageColor != p.Perm || p.Perm == "chatplus.default" && playerData.MessageColor != p.Perm).ToList();
if (aviableMessageColors.Count == 0) {
Reply(player, "NO.AVAILABLE.COLORS");
return;
}
if (args.Length == 1) {
Reply(player, "AVAILABLE.COLORS.MESSAGE", string.Join(", ", aviableMessageColors.Select(p => covalence.FormatText(string.Format(p.Format, p.Arg))).ToArray()));
return;
}
var selectedMessageColor = aviableMessageColors.FirstOrDefault(p => p.Arg == args[1]);
if (selectedMessageColor == null) {
Reply(player, "COLOR.NOT.FOUND", args[1]);
return;
}
playerData.MessageColor = selectedMessageColor.Perm;
Reply(player, "MESSAGE.COLOR.CHANGED", selectedMessageColor.Arg);
return;
default : SendChatHelp(player);
return;
}
}
#endregion
#region Private messaging
private bool PmAvatar() => config.PMAva.HasValue && config.PMAva.Value;
private void RustChat(IPlayer player, string langkey, string avatar, params object[] args) {
var msg = string.Format(GetMsg(langkey, player), args);
player.Command("chat.add", 2, PmAvatar() ? avatar : "0", covalence.FormatText(msg));
}
readonly Dictionary<string, string> pmHistory = new Dictionary<string, string>();
[Command("pm")]
void cmdChatPM(IPlayer player, string cmd, string[] args) {
if (args.Length < 2) {
Reply(player, "CMD.PM.HELP");
return;
}
var argList = args.ToList();
argList.RemoveAt(0);
string message = RemoveTags(string.Join(" ", argList.ToArray()));
var receivers = players.Connected.Where(p => p.Name.ToLower().Contains(args[0].ToLower()) || p.Id == args[0]).ToList();
if (receivers.Count == 0) {
Reply(player, "PLAYER.NOT.FOUND", args[0]);
return;
}
if (receivers.Count > 1) {
Reply(player, "MULTIPLE.PLAYERS.FOUND", string.Join("\n", receivers.Select(p => $"{p.Name} ({p.Id})").ToArray()));
return;
}
IPlayer receiver = receivers[0];
if (receiver.Id == player.Id) {
Reply(player, "PM.SELF");
return;
}
var receiverName = RemoveTags(receiver.Name);
if (GetPlayerData(receiver).BlackList.Contains(player.Id)) {
Reply(player, "PM.YOU.ARE.BLACK.LIST", receiverName);
return;
}
pmHistory[player.Id] = receiver.Id;
pmHistory[receiver.Id] = player.Id;
var targetName = RemoveTags(player.Name);
if (player.IsServer) {
ConsoleIPly = player;
Reply(player, "PM.SENDER.FORMAT", receiverName, message);
RustChat(receiver, "PM.RECEIVER.FORMAT", "0", config.ConsoleName, message);
}
else {
RustChat(player, "PM.SENDER.FORMAT", player.Id, receiverName, message);
RustChat(receiver, "PM.RECEIVER.FORMAT", player.Id, targetName, message);
}
var bply = receiver.Object as BasePlayer;
if (GetPlayerData(receiver).PMSound) {
Effect.server.Run(config.PrivateSoundMessagePath, bply, 0, Vector3.zero, Vector3.zero);
}
Log(LogType.Pm, string.Format(GetMsg("PM.LOG"), $"{targetName}({player.Id})", $"{receiverName}({receiver.Id})", message));
}
[Command("r")]
void cmdChatR(IPlayer player, string cmd, string[] args) {
if (args.Length == 0) {
Reply(player, "CMD.R.HELP");
return;
}
string message = RemoveTags(string.Join(" ", args));
string recieverUserId;
if (!pmHistory.TryGetValue(player.Id, out recieverUserId)) {
Reply(player, "PM.NO.MESSAGES");
return;
}
var playerName = RemoveTags(player.Name);
if (recieverUserId == "server_console") {
RustChat(player, "PM.SENDER.FORMAT", player.Id, config.ConsoleName, message);
Reply(ConsoleIPly, "PM.RECEIVER.FORMAT", playerName, message);
Log(LogType.Pm, string.Format(GetMsg("PM.LOG"), $"{playerName}({player.Id})", $"Server console", message));
return;
}
var receiver = players.Connected.FirstOrDefault(p => p.Id == recieverUserId);
if (receiver == null) {
Reply(player, "PM.PLAYER.LEAVE");
return;
}
var receiverName = RemoveTags(receiver.Name);
if (GetPlayerData(receiver).BlackList.Contains(player.Id)) {
Reply(player, "PM.YOU.ARE.BLACK.LIST", receiverName);
return;
}
if (player.IsServer) {
Reply(player, "PM.SENDER.FORMAT", receiverName, message);
RustChat(receiver, "PM.RECEIVER.FORMAT", "0", config.ConsoleName, message);
}
else {
RustChat(player, "PM.SENDER.FORMAT", player.Id, receiverName, message);
RustChat(receiver, "PM.RECEIVER.FORMAT", player.Id, playerName, message);
}
var bply = receiver.Object as BasePlayer;
if (GetPlayerData(receiver).PMSound) {
Effect.server.Run(config.PrivateSoundMessagePath, bply, 0, Vector3.zero, Vector3.zero);
}
Log(LogType.Pm, string.Format(GetMsg("PM.LOG"), $"{playerName}({player.Id})", $"{receiverName}({receiver.Id})", message));
}
#endregion
#region Data
private class MuteData {
public readonly string Initiator;
public readonly string Reason;
public readonly DateTime ExpireDate;
[JsonIgnore]
private bool Timed => ExpireDate != DateTime.MinValue;
[JsonIgnore]
public bool Expired => Timed && ExpireDate < DateTime.UtcNow;
[JsonIgnore]
public string Remain => Timed ? TimeToString(ExpireDate - DateTime.UtcNow) : "Unlimited";
public static bool IsMuted(string userID, ulong playerid = 0) => mutes.ContainsKey(userID);
public MuteData(string Initiator, string Reason, TimeSpan? Until = null) {
this.ExpireDate = Until.HasValue ? DateTime.UtcNow + Until.Value : DateTime.MinValue;
this.Reason = Reason;
this.Initiator = Initiator;
}
[JsonConstructor]
public MuteData(string Initiator, string Reason, DateTime ExpireDate) {
this.ExpireDate = ExpireDate;
this.Reason = Reason;
this.Initiator = Initiator;
}
public static string TimeToString(TimeSpan elapsedTime) {
int hours = elapsedTime.Hours;
int minutes = elapsedTime.Minutes;
int seconds = elapsedTime.Seconds;
int days = elapsedTime.Days;
string s = "";
if (days > 0) s += $"{days} дн.";
if (hours > 0) s += $"{hours} ч.";
if (minutes > 0) s += $"{minutes} мин.";
if (seconds > 0) s += $"{seconds} сек.";
else s = s.TrimEnd(' ');
return s;
}
public static bool StringToTime(string source, out TimeSpan time) {
int seconds = 0, minutes = 0, hours = 0, days = 0;
Match s = new Regex(@"(\d+?)s", RegexOptions.IgnoreCase).Match(source);
Match m = new Regex(@"(\d+?)m", RegexOptions.IgnoreCase).Match(source);
Match h = new Regex(@"(\d+?)h", RegexOptions.IgnoreCase).Match(source);
Match d = new Regex(@"(\d+?)d", RegexOptions.IgnoreCase).Match(source);
if (s.Success) seconds = Convert.ToInt32(s.Groups[1].ToString());
if (m.Success) minutes = Convert.ToInt32(m.Groups[1].ToString());
if (h.Success) hours = Convert.ToInt32(h.Groups[1].ToString());
if (d.Success) days = Convert.ToInt32(d.Groups[1].ToString());
source = source.Replace(seconds + "s", string.Empty);
source = source.Replace(minutes + "m", string.Empty);
source = source.Replace(hours + "h", string.Empty);
source = source.Replace(days + "d", string.Empty);
if (!string.IsNullOrEmpty(source) || (!s.Success && !m.Success && !h.Success && !d.Success)) {
time = TimeSpan.Zero;
return false;
}
time = new TimeSpan(days, hours, minutes, seconds);
return true;
}
}
public class PlayerData {
public string Prefix = "chatplus.default";
public string NameColor = "chatplus.default";
public string MessageColor = "chatplus.default";
public bool Censor = true;
public bool PMSound = true;
public string Name = "";
public bool IsAdmin = false;
public bool IsModer = false;
public List<string> BlackList = new List<string>();
}
PlayerData GetPlayerData(IPlayer player) {
var data = GetPlayerData(player.Id);
data.Name = player.Name;
return data;
}
PlayerData GetPlayerData(BasePlayer player) {
var data = GetPlayerData(player.UserIDString);
data.Name = player.displayName;
return data;
}
PlayerData GetPlayerData(string userId) {
PlayerData config;
if (PlayersData.TryGetValue(userId, out config)) {
if (config.Prefix != "chatplus.default" && !PermissionService.HasPermission(userId, config.Prefix)) config.Prefix = "chatplus.default";
if (config.NameColor != "chatplus.default" && !PermissionService.HasPermission(userId, config.NameColor)) config.NameColor = "chatplus.default";
if (config.MessageColor != "chatplus.default" && !PermissionService.HasPermission(userId, config.MessageColor)) config.MessageColor = "chatplus.default";
return config;
}
config = new PlayerData();
PlayersData[userId] = config;
return config;
}
PlayerData GetPlayerData(string playerId, string playerName) {
var data = GetPlayerData(playerId);
data.Name = playerName;
return data;
}
#endregion
#region Localization
private string GetMsg(string langKey) => lang.GetMessage(langKey, this);
private string GetMsg(string langKey, BasePlayer player) => lang.GetMessage(langKey, th
// ... [Code preview truncated due to length. Full source in attached file] ...