· 6 years ago · Mar 22, 2020, 04:48 PM
1//#define RUST
2using System;
3using System.Collections.Generic;
4using System.Linq;
5using Newtonsoft.Json;
6using Oxide.Core;
7using Oxide.Core.Configuration;
8using Oxide.Core.Libraries;
9using Oxide.Core.Plugins;
10using System.Text.RegularExpressions;
11using Oxide.Core.Libraries.Covalence;
12using UnityEngine;
13
14namespace Oxide.Plugins
15{
16 [Info("ChatPlus", "", "1.4.0", ResourceId = 82)]
17 // Слив плагинов server-rust by Apolo YouGame
18 public class ChatPlus : CovalencePlugin
19 {
20 /* covalence.FormatText(msg);
21 * Formatter.ToPlaintext(msg);
22 * Original autor: Unknown
23 * Editor: Vlad-00003
24 * Editor info:
25 * E-mail: Vlad-00003@mail.ru
26 * Vk: vk.com/vlad_00003
27 * v1.1.0
28 * Добавлены команды:
29 * chatplus.message {steamid/ник} привилегия
30 * chatplus.name {steamid/ник} привилегия
31 * chatplus.prefix {steamid/ник} привилегия
32 * Данные команды лишь УСТАНАВЛИВАЮТ префикс\цвета игроку. Для использования необходимо выдать игроку
33 * привилегии. Без привилегий команды работать НЕ будут.
34 * Для использования из консоли игрока требуется привилегия на присваивание префикса и цветов (chatplus.assign)
35 * Добавлена возможноть выдавать мут\использовать команды присваивания цветов\префика игрокам, не находящимся на сервере.
36 * Добавлена комманда mutelist - выводит список текущик игроков, у которых заблокирован чат.
37 * При отключении чата игроку сохраняется не только время, а так же то, кто заблокировал игроку чат и причина,
38 * что полностью отражается как в чате и заблокированного, так и при команде mutelist
39 * Отныне при использовании команды mute причина и время опциональны - можно заблокировать человека навсегда, но с причиной.
40 * Примеры:
41 * "mute vlad" - блокировать игроку чат на всегда. Причина - Not specified
42 * "mute vlad 1d" - блокировать чат игроку на 1 день. Причина - Not specified
43 * "mute vlad Просто потому что я так решил." - блокировать чат игроку навсегда. Причина - "Просто потому что я так решил."
44 * "mute vlad 1d Это весомоя причина" - блокировать чат игроку на 1 день. Причина - "Это весомоя причина"
45 * Разделены привилегии на использование команд mute/unmute на две разные привилегии - chatplus.mute и chatplus.unmute соответственно.
46 * Небольшая чистка и оптимизация кода.
47 * V1.1.1
48 * Стандартная причина мута (если не указана) выведена в файл конфигурации
49 * v1.1.2
50 * Добавлен API - private void API_RegisterThirdPartyTitle(Plugin plugin, Func<IPlayer, string> titleGetter)
51 * V1.1.3
52 * Удалена ненужная проверка
53 * V1.2.0
54 * Плагин переведён на тип Covalence - Теперь он может работать не только в Rust-е. Требуется проверка на других играх.
55 * Так же теперь плагин поддерживает стандартизированное форматирование ([#HEXCOLOR][/#] [+SIZE][/+])
56 * Исправлена ошибка при удалении игрока из чёрного списка - теперь сообщение о том, что игрока удалили появляется в нужное время.
57 * Если игрок указал неверный параметр в команде /chat, то ему будет выведена справка. Раньше не выводилось ничего.
58 * Если у вас возникнут ошибки при обновлении до данной версии вы можете сделать следующие - очистить BlackList у каждого игрока
59 * в файле данных. Или просто удалите ChatPlus_Players.json из папки oxide/data.
60 * Для полной совместимости с Clans Reborn вам нужно поправить функцию OnPluginLoaded в плагине Clans:
61 * void OnPluginLoaded(Plugin plugin)
62 * {
63 * if (plugin.Title != "Better Chat" || plugin.Title != "ChatPlus") return;
64 * if (enableClanTagging) Interface.CallHook("API_RegisterThirdPartyTitle", this, new Func<IPlayer, string>(getFormattedClanTag));
65 * }
66 * V1.2.1
67 * Добавлено лоигрование режимов администратора и модератора чата.
68 * V1.2.2
69 * Исправлена ошибка во флаге, Rust заменено на RUST. Из-за этого даже в игре Rust использовались мультиобразные вызовы,
70 * что приводило к отсутствию звуков личных сообщений и отсутствию иконок игроков в чате
71 * Так же исправлена возможность отправлять ЛС самому себе если отображаемое имя на сервере игры RUST отличается от
72 * фактического имени в базе
73 * Добавлен ResourceId
74 * V1.3.0
75 * Добавлена возможность использовать PM через консоль и отвечать через r.
76 * Теперь вы можете отправлять личные сообщения игрокам из консоли, а они могут вам отвечать!
77 * Исправлена ошибка в языковых файлах. Команд присваивания префикса\цветов имён\сообщений в чате
78 * Полностью переписаны языковые файл (Изменён принцип форматирования на стандартизированное представление):
79 * <color=#HEX></color> заменено на [#HEX][/#] и <size=N></size> заменено на [+N][/+]
80 * Удалите ваши старые языковые файлы и перезапустите плагин.
81 * Данное действие ОБЯЗАТЕЛЬНО!
82 * Добавлены новые строки файла конфигурации(пересоздавать ничего не нужно -
83 * они автоматически будут добавлены в конфиг при первом запуске обновлённой версии):
84 * M. Имя консоли при отправке личных сообщений и отключении чата из консоли
85 * N. Формат отправки сообщений из консоли командой say
86 * Имя консоли это то имя, которые будет выводиться при блокировке чата из консоли сервера.
87 * Так же теперь изменению подверглась команда global.say, которую, помимо консоли, могут вызывать администраторы из консоли игры:
88 * Теперь вы можете настроить формат вывода сообщений в чат при использовании данной команды!
89 * {0} - Это имя консоли, из пераметра выше. {1} - само сообщение.
90 * V1.3.1
91 * Добавлена возможность отображение аватарок игрока при отправке личного сообщения(ТОЛЬКО Rust!)
92 * V1.3.2
93 * Переделана система логгирования, теперь так же ведётся лог личных сообщений(что крайне мешает когда ты переписываешься через консоль
94 * я подумаю как это сделать красивее).
95 * Оптимизация функций, отвечающих за отображение иконок в личных переписках.
96 * Проверка на консоль сервера вынесена отдельно
97 * V1.3.3
98 * Теперь в списках имён\префиксов\цветов сообщений отображается default, дабы игрок мог вернуть цвет к стандарту без команды /chat reset
99 * v1.3.4
100 * Исправление v1.3.3 - теперь default видят только те, у кого на данный момент выбран не стандартный цвет\префикс
101 * v1.3.5
102 * Добавлено верное форматирование в функцию BroadcastChat - вывод сообщений в чат о мутах. Теперь она так же поддерживает стандартизированное форматирование.
103 * v1.3.6
104 * Теперь верно получается языковой файл справки о команде /chat
105 * v1.3.7
106 * Попытка исправить NRE в SendChat при вызове SendConsoleCommand
107 * v1.3.71
108 * Убрана устаревшая функция Reply, принимающая как аргумент BasePlayer, упрощён доступ к данным пользователя в команде /chat
109 * v1.3.8
110 * Добавлена возможность скрывать имя администратора, который заблокировал доступ к чату.
111 * v1.3.9
112 * Добавлен API IsPlayerMuted(object ID) - вернёт true если игроку недоступен чат
113 * Добавлен хук OnChatPlusMessage(Dictionary<string,object> dict), доступные параметры:
114 * ["Player"] - Iplayer - игрок, написавший в чат
115 * ["Message"] - string - его сообщение в чат
116 * ["CensoredMessage"] - string - версия его сообщения с цензурой
117 * ["Prefixes"] - string - все префиксы игрока, разделённые одним пробелом.
118 * v1.3.10
119 * Исправил ошибку в хуке
120 * v1.3.11
121 * Добавлена новая строка в языковой файл - сообщение о том, что игрока нет в чёрном списке при использовании /chat ignore remove <name>
122 * Исправлена ошибка, по которой сообщение в чат могло отправляться игроку, которого нет на сервере, что приводило к сбоям в работе плагина.
123 * Проверка IsServerConsole по ID игрока заменена на поле IsServer класса IPlayer.
124 * v1.4.0
125 * Убрана возможность форматирования текста игроками(перед форматированием сообщение очищается от тэегов)
126 * Поправлена цензура чата. Теперь если исключение находиться на нулевой позиции оно так же будет учтено.
127 * Исправлена ошибка из-за которой время блокировки чата не сохранялось при перезагрузках.
128 * Всем администраторам - пересмотрите список тех, кому блокировали чат. Возможно часть из этих блокировок уже давно должна была закончится =)
129 */
130
131 #region Global vars
132 private ChatConfig config;
133 private static ChatPlus m_Instance;
134 private static Dictionary<string, MuteData> mutes = new Dictionary<string, MuteData>();
135 private Dictionary<string, PlayerData> PlayersData = new Dictionary<string, PlayerData>();
136 private PlayerData defaultData = new PlayerData();
137 private bool GlobalMute = false;
138 private bool HasExpired;
139 private IPlayer ConsoleIPly;
140
141 DynamicConfigFile mutes_File = Interface.Oxide.DataFileSystem.GetFile("ChatPlus_Mutes");
142 DynamicConfigFile players_File = Interface.Oxide.DataFileSystem.GetFile("ChatPlus_Players");
143
144 public static Dictionary<Plugin, Func<IPlayer, string>> ThirdPartyTitles = new Dictionary<Plugin, Func<IPlayer, string>>();
145 #endregion
146
147 #region Initialization and quiting
148 void OnServerInitialized()
149 {
150 m_Instance = this;
151 LoadMessages();
152 LoadConfig();
153 LoadData();
154 config.RegisterPerms();
155 timer.Repeat(10, 0, () =>
156 {
157 List<string> expired = mutes.Where(m => m.Value.Expired).Select(m => m.Key).ToList();
158 foreach (string userID in expired)
159 {
160 IPlayer player = players.FindPlayerById(userID.ToString());
161 if (player == null) continue;
162 mutes.Remove(userID);
163 BroadcastChat("MUTE.EXPIRED", player.Name);
164 Log(LogType.Mute, string.Format(GetMsg("MUTE.EXPIRED"), player.Name));
165 if (!HasExpired)
166 HasExpired = true;
167 }
168 if (HasExpired)
169 {
170 SaveMutes();
171 HasExpired = false;
172 }
173 });
174 }
175
176 void Unload()
177 {
178 OnServerSave();
179 }
180 void OnServerSave()
181 {
182 SaveMutes();
183 players_File.WriteObject(PlayersData.Where(p => !p.Value.Equals(defaultData)).ToDictionary(p => p.Key, p => p.Value));
184 }
185 private void SaveMutes()
186 {
187 mutes_File.WriteObject(mutes);
188 }
189 void LoadData()
190 {
191 mutes = mutes_File.ReadObject<Dictionary<string, MuteData>>();
192 PlayersData = players_File.ReadObject<Dictionary<string, PlayerData>>();
193 }
194 #endregion
195
196 #region Chat handling
197 object OnUserChat(IPlayer sender, string message)
198 {
199 if (GlobalMute)
200 {
201 if (!CanMuteAll(sender))
202 {
203 Reply(sender, "MUTE.ALL.DISABLED");
204 return false;
205 }
206 }
207 var pData = GetPlayerData(sender);
208 if (pData.IsAdmin == true)
209 {
210 Log(LogType.Chat, $"[ADMIN MODE] {sender.Name}({sender.Id}): {message}");
211 bool outer;
212 var cens = CensorBadWords(message, out outer);
213 cens = string.Format(config.adminPrivilages.AdminFormat, cens);
214 message = string.Format(config.adminPrivilages.AdminFormat, message);
215 SendChat("", message, cens);
216 return false;
217 }
218 if (pData.IsModer == true)
219 {
220 Log(LogType.Chat, $"[MODERATOR MODE] {sender.Name}({sender.Id}): {message}");
221 bool outer;
222 var cens = CensorBadWords(message, out outer);
223 cens = string.Format(config.adminPrivilages.ModerFormat, cens);
224 message = string.Format(config.adminPrivilages.ModerFormat, message);
225 SendChat("", message, cens);
226 return false;
227 }
228 if (SpamCheck(sender, message) != null) return true;
229 if (MuteCheck(sender) != null) return true;
230
231 if (config.CapsBlock)
232 {
233 message = RemoveCaps(message);
234 }
235 message = RemoveTags(message);
236 bool mute;
237 var censorMessage = CensorBadWords(message, out mute);
238 if (config.BadWordsBlock & mute)
239 {
240 Mute(sender.Id, sender.Name, new TimeSpan(0, 0, config.MuteBadWordsDefault), config.MuteReasonAutoMute, "ChatPlus");
241 }
242 var prefix = config.Get(config.prefixes, pData.Prefix).Format;
243 var nameColor = config.Get(config.names, pData.NameColor).Format;
244 var messageColor = config.Get(config.messages, pData.MessageColor).Format;
245
246 var name = string.Format(nameColor, sender.Name);
247 message = string.Format(messageColor, message);
248 censorMessage = string.Format(messageColor, censorMessage);
249 foreach (var thirdPartyTitle in ThirdPartyTitles)
250 {
251 try
252 {
253 string title = thirdPartyTitle.Value(sender);
254
255 if (!string.IsNullOrEmpty(title))
256 {
257 prefix = title + " " + prefix;
258 }
259 }
260 catch (Exception ex)
261 {
262 PrintError($"Error when trying to get third-party title from plugin '{thirdPartyTitle.Key.Title}'{Environment.NewLine}{ex}");
263 }
264 }
265 Dictionary<string,object> hookDictionary = new Dictionary<string, object>()
266 {
267 ["Player"] = sender,
268 ["Message"] = message,
269 ["CensoredMessage"] = censorMessage,
270 ["Prefixes"] = prefix
271 };
272 foreach (var plugin in plugins.GetAll())
273 {
274 object result = plugin.CallHook("OnChatPlusMessage", hookDictionary);
275 if (result is Dictionary<string, object>)
276 {
277 try
278 {
279 var dict = (Dictionary<string, object>)result;
280 sender = dict["Player"] as IPlayer;
281 message = dict["Message"] as string;
282 censorMessage = dict["CensoredMessage"] as string;
283 prefix = dict["Prefixes"] as string;
284 }
285 catch (Exception ex)
286 {
287 PrintWarning($"Plugin '{plugin.Title}({plugin.Version})' failed to modify the ChatPlus message data. Error:\n{ex.Message}");
288 }
289 }
290 else if(result != null)
291 return null;
292 }
293 if (prefix.Length > 0)
294 name = $"{prefix} {name}";
295 SendChat(name, message, censorMessage, sender.Id);
296 Log(LogType.Chat, $"{name}[{sender.Id}]: {message}");
297 return false;
298 }
299 private string RemoveTags(string message)
300 {
301 List<string> forbiddenTags = new List<string>{
302 "</color>",
303 "</size>",
304 "<b>",
305 "</b>",
306 "<i>",
307 "</i>"
308 };
309 message = Regex.Replace(message, "(<color=.+?>)", string.Empty, RegexOptions.IgnoreCase);
310 message = Regex.Replace(message, "(<size=.+?>)", string.Empty, RegexOptions.IgnoreCase);
311 foreach (string tag in forbiddenTags)
312 message = Regex.Replace(message, tag, string.Empty, RegexOptions.IgnoreCase);
313 return Formatter.ToPlaintext(message);
314 }
315 string RemoveCaps(string message)
316 {
317 var ss = message.Split(' ');
318 for (int j = 0; j < ss.Length; j++)
319 for (int i = 1; i < ss[j].Length; i++)
320 {
321 var sym = ss[j][i];
322 if (char.IsLower(sym)) continue;
323 ss[j] = ss[j].Remove(i, 1);
324 ss[j] = ss[j].Insert(i, char.ToLower(sym).ToString());
325 }
326 return string.Join(" ", ss);
327 }
328
329 bool? MuteCheck(IPlayer sender)
330 {
331 if (MuteData.IsMuted(sender.Id))
332 {
333 MuteData md = mutes[sender.Id];
334 Reply(sender, "YOU.MUTED", md.Initiator, md.Reason, md.Remain);
335 return true;
336 }
337 return null;
338 }
339
340 bool? SpamCheck(IPlayer sender, string message)
341 {
342 if (message.Length > 500)
343 {
344 sender.Kick(GetMsg("CHAT.TOOMUCH", sender));
345 return false;
346 }
347 if (message.Length > 100)
348 {
349 Reply(sender, "CHAT.SPAM");
350 return false;
351 }
352 return null;
353 }
354 public string CensorBadWords(string input, out bool found)
355 {
356 found = false;
357 string temp = input.ToLower();
358 foreach (var swear in config.badWords)
359 {
360 var firstIndex = temp.IndexOf(swear.Key);
361 if (firstIndex >= 0 && swear.Value.All(exception => temp.IndexOf(exception) <= 0))
362 while (firstIndex < input.Length && input[firstIndex] != ' ')
363 {
364 input = input.Remove(firstIndex, 1);
365 input = input.Insert(firstIndex, "*");
366 firstIndex++;
367 found = true;
368 }
369 }
370 return input;
371 }
372 #endregion
373
374 #region Logging
375 enum LogType
376 {
377 Chat,
378 Mute,
379 PM,
380 ServerConsole
381 }
382 private void Log(LogType type, string msg)
383 {
384 switch (type)
385 {
386 case LogType.Chat:
387 Interface.Oxide.RootLogger.Write(Oxide.Core.Logging.LogType.Info, $"[CHAT] {Formatter.ToPlaintext(msg)}");
388 // Слив плагинов server-rust by Apolo YouGame
389 return;
390 case LogType.Mute:
391 Interface.Oxide.RootLogger.Write(Oxide.Core.Logging.LogType.Info, $"[MUTE] {Formatter.ToPlaintext(msg)}");
392 // Слив плагинов server-rust by Apolo YouGame
393 return;
394 case LogType.PM:
395 Interface.Oxide.RootLogger.Write(Oxide.Core.Logging.LogType.Info, $"[PM] {Formatter.ToPlaintext(msg)}");
396 // Слив плагинов server-rust by Apolo YouGame
397 return;
398 case LogType.ServerConsole:
399 Interface.Oxide.RootLogger.Write(Oxide.Core.Logging.LogType.Info, $"[ServerConsole] {Formatter.ToPlaintext(msg)}");
400 // Слив плагинов server-rust by Apolo YouGame
401 return;
402 }
403 }
404 #endregion
405
406 #region Broadcasting
407 void SendChat(string name, string message, string censorMessage = "", string userId = "0")
408 {
409 name = covalence.FormatText(name);
410 message = covalence.FormatText(message);
411 censorMessage = covalence.FormatText(censorMessage);
412 if (string.IsNullOrEmpty(censorMessage)) censorMessage = message;
413#if RUST
414 foreach (var player in BasePlayer.activePlayerList)
415 {
416 string msg = GetPlayerData(player).Censor ? censorMessage : message;
417 player?.SendConsoleCommand("chat.add", userId,
418 string.IsNullOrEmpty(name) ? $"{msg}" : $"{name}: {msg}");
419 }
420#else
421 foreach (var player in players.Connected)
422 {
423 string msg = GetPlayerData(player).Censor ? censorMessage : message;
424 player.Message(string.IsNullOrEmpty(name) ? $"{msg}" : $"{name}: {msg}");
425 }
426#endif
427 }
428 void BroadcastChat(string langKey, params object[] args)
429 {
430 foreach (var player in BasePlayer.activePlayerList)
431 {
432 player.ChatMessage(covalence.FormatText(string.Format(GetMsg(langKey, player), args)));
433 }
434 }
435 private void Reply(IPlayer player, string langkey, params object[] args)
436 {
437 string message = string.Format(GetMsg(langkey, player.Id), args);
438 message = player.IsServer ? Formatter.ToPlaintext(message) : covalence.FormatText(message);
439 if(player.IsServer | player.IsConnected)
440 player.Reply(message);
441 }
442 #endregion
443
444 #region Sub functions
445 void Mute(string userID, string name, TimeSpan? time = null, string reason = null, string sender = null)
446 {
447 if (string.IsNullOrEmpty(sender)) sender = "Not specified";
448 if (string.IsNullOrEmpty(reason)) reason = config.MuteReason;
449 string log;
450 if (!time.HasValue)
451 {
452 mutes[userID] = new MuteData(sender, reason);
453 BroadcastChat("USER.MUTED.REASON", sender, name, reason, "Unlimited");
454 log = string.Format(GetMsg("USER.MUTED.LOG"), sender, name, "Unlimited", reason);
455 }
456 else
457 {
458 mutes[userID] = new MuteData(sender, reason, time.Value);
459 BroadcastChat("USER.MUTED.REASON", sender, name, reason, MuteData.TimeToString(time.Value));
460 log = string.Format(GetMsg("USER.MUTED.LOG"), sender, name, MuteData.TimeToString(time.Value), reason);
461 }
462 Log(LogType.Mute, log);
463 SaveMutes();
464 }
465 private Dictionary<string, string> GetPlayers(string NameOrID)
466 {
467 var pl = players.FindPlayers(NameOrID).ToList();
468 return pl.Select(p => new KeyValuePair<string, string>(p.Id, p.Name)).ToDictionary(x => x.Key, x => x.Value);
469 }
470 private void SendChatHelp(IPlayer player)
471 {
472 string msg = GetMsg("CMD.CHAT.HELP", player.Id);
473 if (CanMuteAll(player)) msg += GetMsg("CMD.MUTE.ALL.HELP", player.Id);
474 if (IsAdmin(player)) msg += GetMsg("CMD.CHAT.HELP.PERMISSION.ADMIN", player.Id);
475 if (IsModerator(player)) msg += GetMsg("CMD.CHAT.HELP.PERMISSION.MODERATOR", player.Id);
476 msg = player.IsServer ? Formatter.ToPlaintext(msg) : covalence.FormatText(msg);
477 player.Message(msg);
478 }
479 #endregion
480
481 #region Flags
482 bool IsModerator(IPlayer player) => PermissionService.HasPermission(player.Id, config.adminPrivilages.ModerPermiss) || player.IsAdmin;//player.net.connection.authLevel >= 1;
483 bool IsAdmin(IPlayer player) => PermissionService.HasPermission(player.Id, config.adminPrivilages.AdminPermiss) || player.IsAdmin;//player.net.connection.authLevel >= 2;
484 bool CanMute(IPlayer player) => PermissionService.HasPermission(player.Id, config.adminPrivilages.MutePermiss) || player.IsAdmin;//player.net.connection.authLevel >= 1;
485 bool CanMuteAll(IPlayer player) => PermissionService.HasPermission(player.Id, config.adminPrivilages.MuteAllPermiss) || player.IsAdmin;//player.net.connection.authLevel >= 2;
486 bool CanAssign(IPlayer player) => PermissionService.HasPermission(player.Id, config.adminPrivilages.AssignPermiss) || player.IsAdmin;//player.net.connection.authLevel >= 2;
487 bool CanUnMute(IPlayer player) => PermissionService.HasPermission(player.Id, config.adminPrivilages.UnMutePermiss) || player.IsAdmin;//player.net.connection.authLevel >= 1;
488 #endregion
489
490 #region Commands
491#if RUST
492 object OnServerCommand(ConsoleSystem.Arg arg)
493 {
494 if (arg?.cmd?.FullName != null && arg?.cmd?.FullName == "global.say")
495 {
496 if (!arg.HasArgs())
497 return false;
498 string message = string.Join(" ", arg.Args);
499
500 bool outer;
501 var cens = CensorBadWords(message, out outer);
502 cens = string.Format(config.ConsoleFormat, config.ConsoleName, cens);
503 message = string.Format(config.ConsoleFormat, config.ConsoleName, message);
504 Log(LogType.ServerConsole, message);
505 SendChat("", message, cens);
506 return true;
507 }
508 else return null;
509 }
510#endif
511
512 [Command("chatplus.prefix")]
513 private void cmdConsolePrefix(IPlayer player, string cmd, string[] Args)
514 {
515 if (!CanAssign(player))
516 {
517 Reply(player, "NO.ACCESS");
518 return;
519 }
520 if (Args == null || Args.Length < 2)
521 {
522 Reply(player, "CMD.HELP.PREFIX");
523 return;
524 }
525 var recivers = GetPlayers(Args[0]);
526 if (recivers == null || recivers.Count == 0)
527 {
528 Reply(player, "PLAYER.NOT.FOUND", Args[0]);
529 return;
530 }
531 if (recivers.Count > 1)
532 {
533 Reply(player, "MULTIPLE.PLAYERS.FOUND", string.Join("\n", recivers.Select(p => $"{p.Value} ({p.Key})").ToArray()));
534 return;
535 }
536 var target = recivers.First();
537 var pdata = GetPlayerData(target.Key);
538 if (!PermissionService.HasPermission(target.Key, Args[1]))
539 {
540 Reply(player, "NO.PERMISSION.PLAYER");
541 return;
542 }
543 pdata.Prefix = Args[1];
544 Reply(player, "PREFIX.CHANGED", Args[1]);
545 }
546 [Command("chatplus.name")]
547 private void cmdConsoleName(IPlayer player, string cmd, string[] Args)
548 {
549 if (!CanAssign(player))
550 {
551 Reply(player, "NO.ACCESS");
552 return;
553 }
554 if (Args == null || Args.Length < 2)
555 {
556 Reply(player, "CMD.HELP.NAME");
557 return;
558 }
559 var recivers = GetPlayers(Args[0]);
560 if (recivers == null || recivers.Count == 0)
561 {
562 Reply(player, "PLAYER.NOT.FOUND", Args[0]);
563 return;
564 }
565 if (recivers.Count > 1)
566 {
567 Reply(player, "MULTIPLE.PLAYERS.FOUND", string.Join("\n", recivers.Select(p => $"{p.Value} ({p.Key})").ToArray()));
568 return;
569 }
570 var target = recivers.First();
571 var pdata = GetPlayerData(target.Key);
572 if (!PermissionService.HasPermission(target.Key, Args[1]))
573 {
574 Reply(player, "NO.PERMISSION.PLAYER");
575 return;
576 }
577 pdata.NameColor = Args[1];
578 Reply(player, "NAME.COLOR.CHANGED", Args[1]);
579 }
580 [Command("chatplus.message")]
581 private void cmdConsoleMessage(IPlayer player, string cmd, string[] Args)
582 {
583 if (!CanAssign(player))
584 {
585 Reply(player, "NO.ACCESS");
586 return;
587 }
588 if (Args == null || Args.Length < 2)
589 {
590 Reply(player, "CMD.HELP.MESSAGE");
591 return;
592 }
593 var recivers = GetPlayers(Args[0]);
594 if (recivers == null || recivers.Count == 0)
595 {
596 Reply(player, "PLAYER.NOT.FOUND", Args[0]);
597 return;
598 }
599 if (recivers.Count > 1)
600 {
601 Reply(player, "MULTIPLE.PLAYERS.FOUND", string.Join("\n", recivers.Select(p => $"{p.Value} ({p.Key})").ToArray()));
602 return;
603 }
604 var target = recivers.First();
605 var pdata = GetPlayerData(target.Key);
606 if (!PermissionService.HasPermission(target.Key, Args[1]))
607 {
608 Reply(player, "NO.PERMISSIO.PLAYERN");
609 return;
610 }
611 pdata.MessageColor = Args[1];
612 Reply(player, "MESSAGE.COLOR.CHANGED", Args[1]);
613 }
614 [Command("muteall")]
615 private void cmdChatMuteAll(IPlayer player, string cmd, string[] Args)
616 {
617 if (!CanMuteAll(player))
618 {
619 Reply(player, "NO.ACCESS");
620 return;
621 }
622 if (GlobalMute)
623 {
624 BroadcastChat("MUTE.ALL.ENABLED");
625 GlobalMute = false;
626 return;
627 }
628 BroadcastChat("MUTE.ALL.DISABLED");
629 GlobalMute = true;
630 return;
631 }
632 [Command("mutelist")]
633 void cmdChatMuteList(IPlayer player, string cmd, string[] Args)
634 {
635 if (!CanMute(player) || !CanUnMute(player))
636 {
637 Reply(player, "NO.ACCESS");
638 return;
639 }
640 string msg;
641 if (mutes.Count == 0)
642 msg = GetMsg("MUTE.LIST.NOONE");
643 else
644 {
645 msg = GetMsg("MUTE.LIST.HEAD");
646 foreach (var mute in mutes)
647 {
648 msg += "\n" + string.Format(GetMsg("MUTE.LIST.BODY", player.Id), mute.Value.Initiator, $"{players.FindPlayerById(mute.Key.ToString()).Name} ({mute.Key})", mute.Value.Reason, mute.Value.Remain);
649 }
650 }
651 player.Reply(msg);
652 }
653 [Command("mute")]
654 void cmdChatMute(IPlayer player, string cmd, string[] args)
655 {
656 if (!CanMute(player))
657 {
658 Reply(player, "NO.ACCESS");
659 return;
660 }
661 if (args.Length < 1)
662 {
663 Reply(player, "CMD.MUTE.HELP");
664 return;
665 }
666 var recivers = GetPlayers(args[0]);
667 if (recivers == null || recivers.Count == 0)
668 {
669 Reply(player, "PLAYER.NOT.FOUND", args[0]);
670 return;
671 }
672 if (recivers.Count > 1)
673 {
674 Reply(player, "MULTIPLE.PLAYERS.FOUND", string.Join("\n", recivers.Select(p => $"{p.Value} ({p.Key})").ToArray()));
675 return;
676 }
677 var mutePlayer = recivers.First();
678 if (MuteData.IsMuted(mutePlayer.Key))
679 {
680 Reply(player, "USER.ALREADY.MUTED", mutePlayer.Value, mutes[mutePlayer.Key].Reason, mutes[mutePlayer.Key].Remain);
681 return;
682 }
683 TimeSpan time;
684 string sender = player.IsServer ? config.ConsoleName : player.Name;
685 if (config.adminPrivilages.HideAdmins.HasValue && config.adminPrivilages.HideAdmins.Value && !player.IsServer)
686 sender = config.adminPrivilages.AdminReplace;
687 if (args.Length == 1)
688 {
689 Mute(mutePlayer.Key, mutePlayer.Value, null, null, sender);
690 return;
691 }
692 if (MuteData.StringToTime(args[1], out time))
693 {
694 Mute(mutePlayer.Key, mutePlayer.Value, time, string.Join(" ", args.Skip(2).ToArray()), sender);
695 return;
696 }
697 Mute(mutePlayer.Key, mutePlayer.Value, null, string.Join(" ", args.Skip(1).ToArray()), sender);
698 }
699 [Command("unmute")]
700 void cmdChatUnMute(IPlayer player, string cmd, string[] args)
701 {
702 if (!CanUnMute(player))
703 {
704 Reply(player, "NO.ACCESS");
705 return;
706 }
707 if (args.Length == 0)
708 {
709 Reply(player, "CMD.UNMUTE.HELP");
710 return;
711 }
712 var recivers = GetPlayers(args[0]);
713 if (recivers == null || recivers.Count == 0)
714 {
715 Reply(player, "PLAYER.NOT.FOUND", args[0]);
716 return;
717 }
718 recivers = recivers.Where(p => mutes.ContainsKey(p.Key)).ToDictionary(x => x.Key, x => x.Value);
719 if (recivers == null || recivers.Count == 0)
720 {
721 Reply(player, "PLAYER.NOT.MUTED");
722 return;
723 }
724 if (recivers.Count > 1)
725 {
726 Reply(player, "MULTIPLE.PLAYERS.FOUND", string.Join("\n", recivers.Select(p => $"{p.Value} ({p.Key})").ToArray()));
727 return;
728 }
729 var mutePlayer = recivers.First();
730 mutes.Remove(mutePlayer.Key);
731 BroadcastChat("USER.UNMUTED", player.Name, mutePlayer.Value);
732 string log = GetMsg("USER.UNMUTED.LOG");
733 log = string.Format(log, player.Name, mutePlayer.Value);
734 Log(LogType.Mute, log);
735 SaveMutes();
736 }
737 [Command("chat")]
738 void cmdChat(IPlayer player, string cmd, string[] args)
739 {
740 if (args.Length == 0)
741 {
742 SendChatHelp(player);
743 return;
744 }
745 var playerData = GetPlayerData(player);
746 switch (args[0])
747 {
748 case "reset":
749 PlayersData[player.Id] = new PlayerData();
750 Reply(player, "RESET.SUCCESSFULL");
751 return;
752 case "admin":
753 if (!IsAdmin(player))
754 {
755 Reply(player, "NO.ACCESS");
756 return;
757 }
758 if (playerData.IsAdmin)
759 {
760 playerData.IsAdmin = false;
761 Reply(player, "ADMIN.DISABLE");
762 return;
763 }
764 playerData.IsAdmin = true;
765 Reply(player, "ADMIN.ENABLE");
766 return;
767 case "moder":
768 if (!IsModerator(player))
769 {
770 Reply(player, "NO.ACCESS");
771 return;
772 }
773 if (playerData.IsModer)
774 {
775 playerData.IsModer = false;
776 Reply(player, "MODERATOR.DISABLE");
777 return;
778 }
779 playerData.IsModer = true;
780 Reply(player, "MODERATOR.ENABLE");
781 return;
782 case "censor":
783 if (playerData.Censor)
784 {
785 playerData.Censor = false;
786 Reply(player, "CENSOR.DISABLED");
787 return;
788 }
789 playerData.Censor = true;
790 Reply(player, "CENSOR.ENABLED");
791 return;
792 case "ignore":
793 if (args.Length == 2 && args[1] == "list")
794 {
795 if (playerData.BlackList.Count == 0)
796 {
797 Reply(player, "IGNORE.LIST.IS.EMPTY");
798 return;
799 }
800 Reply(player, "IGNORE.LIST", string.Join(", ", playerData.BlackList.Select(p => GetPlayerData(p).Name).ToArray()));
801 return;
802 }
803 if (args.Length < 3 || (args[1] != "add" && args[1] != "remove"))
804 {
805 Reply(player, "CMD.CHAT.IGNORE.HELP");
806 return;
807 }
808 bool mode = args[1] == "add" ? true : false;
809 var reply = 777;
810 var recivers = players.FindPlayers(args[2]);
811 if (recivers == null || !recivers.Any())
812 {
813 Reply(player, "PLAYER.NOT.FOUND", args[2]);
814 return;
815 }
816 if (recivers.Count() > 1)
817 {
818 Reply(player, "MULTIPLE.PLAYERS.FOUND", string.Join("\n", recivers.Select(p => $"{p.Name} ({p.Id})").ToArray()));
819 return;
820 }
821 var ignorePlayer = recivers.First();
822 if (mode)
823 {
824 if (!playerData.BlackList.Contains(ignorePlayer.Id))
825 {
826 playerData.BlackList.Add(ignorePlayer.Id);
827 Reply(player, "USER.ADD.IGNORE.LIST", ignorePlayer.Name);
828 if (ignorePlayer.IsConnected)
829 Reply(ignorePlayer, "YOU.ADD.IGNORE.LIST", player.Name);
830 return;
831 }
832 Reply(player, "USER.IS.IGNORE.LIST", ignorePlayer.Name);
833 return;
834 }
835 else
836 {
837 if (playerData.BlackList.Contains(ignorePlayer.Id))
838 {
839 playerData.BlackList.Remove(ignorePlayer.Id);
840 Reply(player, "USER.REMOVE.IGNORE.LIST", ignorePlayer.Name);
841 Reply(ignorePlayer, "YOU.REMOVE.IGNORE.LIST", player.Name);
842 return;
843 }
844 Reply(player, "NOT.ON.IGNORE.LIST",ignorePlayer.Name);
845 return;
846 }
847 case "sound":
848 if (args.Length == 1 || (args[1] != "on" && args[1] != "off"))
849 {
850 Reply(player, "CMD.CHAT.SOUND.HELP");
851 return;
852 }
853 bool pmSound = args[1] == "on";
854 playerData.PMSound = pmSound;
855 if (pmSound)
856 {
857 Reply(player, "SOUND.ENABLED");
858 return;
859 }
860 else
861 {
862 Reply(player, "SOUND.DISABLED");
863 return;
864 }
865 case "prefix":
866 var aviablePrefixes = config.prefixes
867 .Where(p => PermissionService.HasPermission(player.Id, p.Perm) && playerData.Prefix != p.Perm
868 || p.Perm == "chatplus.default" && playerData.Prefix != p.Perm).ToList();
869 if (aviablePrefixes.Count == 0)
870 {
871 Reply(player, "NO.AVAILABLE.PREFIXS");
872 return;
873 }
874 if (args.Length == 1)
875 {
876 Reply(player, "AVAILABLE.COLORS.PREFIX",
877 string.Join(", ", aviablePrefixes.Select(p => $"{p.Arg}({covalence.FormatText(p.Format)})").ToArray()));
878 return;
879 }
880 var selectedPrefix = aviablePrefixes.FirstOrDefault(p => p.Arg == args[1]);
881 if (selectedPrefix == null)
882 {
883 Reply(player, "PREFIX.NOT.FOUND", args[1]);
884 return;
885 }
886 playerData.Prefix = selectedPrefix.Perm;
887 Reply(player, "PREFIX.CHANGED", selectedPrefix.Arg);
888 return;
889 case "name":
890 var aviableNameColors = config.names
891 .Where(p => PermissionService.HasPermission(player.Id, p.Perm) && playerData.NameColor != p.Perm
892 || p.Perm == "chatplus.default" && playerData.NameColor != p.Perm).ToList();
893 if (aviableNameColors.Count == 0)
894 {
895 Reply(player, "NO.AVAILABLE.COLORS");
896 return;
897 }
898 if (args.Length == 1)
899 {
900 Reply(player, "AVAILABLE.COLORS.NAME",
901 string.Join(", ", aviableNameColors.Select(p => covalence.FormatText(string.Format(p.Format, p.Arg))).ToArray()));
902 return;
903 }
904 var selectedNameColor = aviableNameColors.FirstOrDefault(p => p.Arg == args[1]);
905 if (selectedNameColor == null)
906 {
907 Reply(player, "COLOR.NOT.FOUND", args[1]);
908 return;
909 }
910 playerData.NameColor = selectedNameColor.Perm;
911 Reply(player, "NAME.COLOR.CHANGED", selectedNameColor.Arg);
912 return;
913 case "message":
914 var aviableMessageColors = config.messages
915 .Where(p => PermissionService.HasPermission(player.Id, p.Perm) && playerData.MessageColor != p.Perm
916 || p.Perm == "chatplus.default" && playerData.MessageColor != p.Perm).ToList();
917 if (aviableMessageColors.Count == 0)
918 {
919 Reply(player, "NO.AVAILABLE.COLORS");
920 return;
921 }
922 if (args.Length == 1)
923 {
924 Reply(player, "AVAILABLE.COLORS.MESSAGE",
925 string.Join(", ", aviableMessageColors.Select(p => covalence.FormatText(string.Format(p.Format, p.Arg))).ToArray()));
926 return;
927 }
928 var selectedMessageColor = aviableMessageColors.FirstOrDefault(p => p.Arg == args[1]);
929 if (selectedMessageColor == null)
930 {
931 Reply(player, "COLOR.NOT.FOUND", args[1]);
932 return;
933 }
934 playerData.MessageColor = selectedMessageColor.Perm;
935 Reply(player, "MESSAGE.COLOR.CHANGED", selectedMessageColor.Arg);
936 return;
937 default:
938 SendChatHelp(player);
939 return;
940 }
941 }
942 #endregion
943
944 #region Private messaging
945#if RUST
946 private bool PmAvatar() => config.PMAva.HasValue && config.PMAva.Value;
947 private void RustChat(IPlayer player, string langkey, string avatar, params object[] args)
948 {
949 var msg = string.Format(GetMsg(langkey, player.Id), args);
950 player.Command("chat.add", PmAvatar() ? avatar : "0", covalence.FormatText(msg));
951 }
952#endif
953 Dictionary<string, string> pmHistory = new Dictionary<string, string>();
954 [Command("pm")]
955 void cmdChatPM(IPlayer player, string cmd, string[] args)
956 {
957 if (args.Length < 2)
958 {
959 Reply(player, "CMD.PM.HELP");
960 return;
961 }
962 var argList = args.ToList();
963 argList.RemoveAt(0);
964 string message = string.Join(" ", argList.ToArray());
965 var receivers = players.Connected.Where(p => p.Name.ToLower()
966 .Contains(args[0].ToLower()) || p.Id == args[0]).ToList();
967 if (receivers == null || receivers.Count == 0)
968 {
969 Reply(player, "PLAYER.NOT.FOUND", args[0]);
970 return;
971 }
972 if (receivers.Count > 1)
973 {
974 Reply(player, "MULTIPLE.PLAYERS.FOUND", string.Join("\n", receivers.Select(p => $"{p.Name} ({p.Id})").ToArray()));
975 return;
976 }
977 IPlayer receiver = receivers[0];
978 if (receiver.Id == player.Id)
979 {
980 Reply(player, "PM.SELF");
981 return;
982 }
983 if (GetPlayerData(receiver).BlackList.Contains(player.Id))
984 {
985 Reply(player, "PM.YOU.ARE.BLACK.LIST", receiver.Name);
986 return;
987 }
988 pmHistory[player.Id] = receiver.Id;
989 pmHistory[receiver.Id] = player.Id;
990#if RUST
991 string msg;
992
993 if (player.IsServer)
994 {
995 ConsoleIPly = player;
996 Reply(player, "PM.SENDER.FORMAT", receiver.Name, message);
997 RustChat(receiver, "PM.RECEIVER.FORMAT", "0", config.ConsoleName, message);
998 }
999 else
1000 {
1001 RustChat(player, "PM.SENDER.FORMAT", player.Id, receiver.Name, message);
1002 RustChat(receiver, "PM.RECEIVER.FORMAT", player.Id, player.Name, message);
1003 }
1004
1005 var bply = receiver.Object as BasePlayer;
1006 if (GetPlayerData(receiver).PMSound)
1007 {
1008 Effect.server.Run(strName: config.PrivateSoundMessagePath, ent: bply, boneID: 0, posLocal: Vector3.zero, normLocal: Vector3.zero);
1009 }
1010#else
1011 Reply(player, "PM.SENDER.FORMAT", receiver.Name, message);
1012 if (player.IsServer)
1013 {
1014 ConsoleIPly = player;
1015 Reply(receiver, "PM.RECEIVER.FORMAT", config.ConsoleName, message);
1016 }
1017 else
1018 Reply(receiver, "PM.RECEIVER.FORMAT", player.Name, message);
1019#endif
1020 Log(LogType.PM, string.Format(GetMsg("PM.LOG"), $"{player.Name}({player.Id})", $"{receiver.Name}({receiver.Id})", message));
1021 }
1022 [Command("r")]
1023 void cmdChatR(IPlayer player, string cmd, string[] args)
1024 {
1025 if (args.Length == 0)
1026 {
1027 Reply(player, "CMD.R.HELP");
1028 return;
1029 }
1030 string message = string.Join(" ", args);
1031
1032 string recieverUserId;
1033 if (!pmHistory.TryGetValue(player.Id, out recieverUserId))
1034 {
1035 Reply(player, "PM.NO.MESSAGES");
1036 return;
1037 }
1038 if (recieverUserId== "server_console")
1039 {
1040#if RUST
1041 RustChat(player, "PM.SENDER.FORMAT", player.Id, config.ConsoleName, message);
1042#else
1043 Reply(player, "PM.SENDER.FORMAT", config.ConsoleName, message);
1044#endif
1045 Reply(ConsoleIPly, "PM.RECEIVER.FORMAT", player.Name, message);
1046 Log(LogType.PM, string.Format(GetMsg("PM.LOG"), $"{player.Name}({player.Id})", $"Server console", message));
1047 return;
1048 }
1049
1050 var receiver = players.Connected.FirstOrDefault(p => p.Id == recieverUserId);
1051 if (receiver == null)
1052 {
1053 Reply(player, "PM.PLAYER.LEAVE");
1054 return;
1055 }
1056 if (GetPlayerData(receiver).BlackList.Contains(player.Id))
1057 {
1058 Reply(player, "PM.YOU.ARE.BLACK.LIST", receiver.Name);
1059 return;
1060 }
1061#if RUST
1062 if (player.IsServer)
1063 {
1064 Reply(player, "PM.SENDER.FORMAT", receiver.Name, message);
1065 RustChat(receiver, "PM.RECEIVER.FORMAT", "0", config.ConsoleName, message);
1066 }
1067 else
1068 {
1069 RustChat(player, "PM.SENDER.FORMAT", player.Id, receiver.Name, message);
1070 RustChat(receiver, "PM.RECEIVER.FORMAT", player.Id, player.Name, message);
1071 }
1072 var bply = receiver.Object as BasePlayer;
1073 if (GetPlayerData(receiver).PMSound)
1074 {
1075 Effect.server.Run(strName: config.PrivateSoundMessagePath, ent: bply, boneID: 0, posLocal: Vector3.zero, normLocal: Vector3.zero);
1076 }
1077#else
1078 Reply(player, "PM.SENDER.FORMAT", receiver.Name, message);
1079 Reply(receiver, "PM.RECEIVER.FORMAT", player.IsServer ? config.ConsoleName : player.Name, message);
1080#endif
1081 Log(LogType.PM, string.Format(GetMsg("PM.LOG"), $"{player.Name}({player.Id})", $"{receiver.Name}({receiver.Id})", message));
1082 }
1083 #endregion
1084
1085 #region Data
1086 private class MuteData
1087 {
1088 public readonly string Initiator;
1089 public readonly string Reason;
1090 public readonly DateTime ExpireDate;
1091 [JsonIgnore]
1092 private bool Timed => ExpireDate != DateTime.MinValue;
1093 [JsonIgnore]
1094 public bool Expired => Timed && ExpireDate < DateTime.UtcNow;
1095 [JsonIgnore]
1096 public string Remain => Timed ? TimeToString(ExpireDate - DateTime.UtcNow) : "Unlimited";
1097 public static bool IsMuted(string userID) => mutes.ContainsKey(userID);
1098 public MuteData(string Initiator, string Reason, TimeSpan? Until = null)
1099 {
1100 this.ExpireDate = Until.HasValue ? DateTime.UtcNow + Until.Value : DateTime.MinValue;
1101 this.Reason = Reason;
1102 this.Initiator = Initiator;
1103 }
1104 [JsonConstructor]
1105 public MuteData(string Initiator, string Reason, DateTime ExpireDate)
1106 {
1107 Interface.Oxide.RootLogger.Write(Core.Logging.LogType.Chat,$"Mutedata initilizere called with: {Initiator} | {Reason} | {ExpireDate}");
1108 this.ExpireDate = ExpireDate;
1109 this.Reason = Reason;
1110 this.Initiator = Initiator;
1111 }
1112
1113 public static string TimeToString(TimeSpan elapsedTime)
1114 {
1115 int hours = elapsedTime.Hours;
1116 int minutes = elapsedTime.Minutes;
1117 int seconds = elapsedTime.Seconds;
1118 int days = elapsedTime.Days;
1119 string s = "";
1120 if (days > 0) s += $"{days} дн. ";
1121 if (hours > 0) s += $"{hours} ч. ";
1122 if (minutes > 0) s += $"{minutes} мин. ";
1123 if (seconds > 0) s += $"{seconds} сек.";
1124 else s = s.TrimEnd(' ');
1125 return s;
1126 }
1127 public static bool StringToTime(string source, out TimeSpan time)
1128 {
1129 int seconds = 0, minutes = 0, hours = 0, days = 0;
1130 Match s = new Regex(@"(\d+?)s", RegexOptions.IgnoreCase).Match(source);
1131 Match m = new Regex(@"(\d+?)m", RegexOptions.IgnoreCase).Match(source);
1132 Match h = new Regex(@"(\d+?)h", RegexOptions.IgnoreCase).Match(source);
1133 Match d = new Regex(@"(\d+?)d", RegexOptions.IgnoreCase).Match(source);
1134 if (s.Success)
1135 seconds = Convert.ToInt32(s.Groups[1].ToString());
1136 if (m.Success)
1137 minutes = Convert.ToInt32(m.Groups[1].ToString());
1138 if (h.Success)
1139 hours = Convert.ToInt32(h.Groups[1].ToString());
1140 if (d.Success)
1141 days = Convert.ToInt32(d.Groups[1].ToString());
1142 source = source.Replace(seconds + "s", string.Empty);
1143 source = source.Replace(minutes + "m", string.Empty);
1144 source = source.Replace(hours + "h", string.Empty);
1145 source = source.Replace(days + "d", string.Empty);
1146 if (!string.IsNullOrEmpty(source) || (!s.Success && !m.Success && !h.Success && !d.Success))
1147 {
1148 time = TimeSpan.Zero;
1149 return false;
1150 }
1151 time = new TimeSpan(days, hours, minutes, seconds);
1152 return true;
1153 }
1154 }
1155 public class PlayerData
1156 {
1157 public string Prefix = "chatplus.default";
1158 public string NameColor = "chatplus.default";
1159 public string MessageColor = "chatplus.default";
1160 public bool Censor = true;
1161 public bool PMSound = true;
1162 public string Name = "";
1163 public bool IsAdmin = false;
1164 public bool IsModer = false;
1165 public List<string> BlackList = new List<string>();
1166 }
1167
1168 PlayerData GetPlayerData(IPlayer player)
1169 {
1170 var data = GetPlayerData(player.Id);
1171 data.Name = player.Name;
1172 return data;
1173 }
1174 PlayerData GetPlayerData(BasePlayer player)
1175 {
1176 var data = GetPlayerData(player.UserIDString);
1177 data.Name = player.displayName;
1178 return data;
1179 }
1180 PlayerData GetPlayerData(string userId)
1181 {
1182 PlayerData config;
1183 if (PlayersData.TryGetValue(userId, out config))
1184 {
1185 if (config.Prefix != "chatplus.default" && !PermissionService.HasPermission(userId, config.Prefix)) config.Prefix = "chatplus.default";
1186 if (config.NameColor != "chatplus.default" && !PermissionService.HasPermission(userId, config.NameColor)) config.NameColor = "chatplus.default";
1187 if (config.MessageColor != "chatplus.default" && !PermissionService.HasPermission(userId, config.MessageColor)) config.MessageColor = "chatplus.default";
1188 return config;
1189 }
1190 config = new PlayerData();
1191 PlayersData[userId] = config;
1192 return config;
1193 }
1194 #endregion
1195
1196 #region Localization
1197 string GetMsg(string key, object ID = null, params object[] args) => lang.GetMessage(key, this, ID == null ? null : ID.ToString());
1198 private void LoadMessages()
1199 {
1200 lang.RegisterMessages(new Dictionary<string, string>()
1201 {
1202 ["CMD.CHAT.HELP"] = "Available commands:\n[#00FF00]/chat censor[/#] - switching chat censor\n[#00FF00]/chat prefix[/#] - switching your chat prefix\n[#00FF00]/chat name[/#] - switching your chat name color\n[#00FF00]/chat message[/#] - switching your chat message color\n[#00FF00]/chat ignore[/#] [#42f4ee]add/remove/list[/#] - managing black list\n[#00FF00]/chat sound[/#] [#42f4ee]on/off[/#] - switching private messages sounds\n[#00FF00]/chat reset[/#] - set your chat/message color and prefix to default",
1203 ["CMD.CHAT.HELP.PERMISSION.ADMIN"] = "\n[#00FF00]/chat admin[/#] - administrator mode",
1204 ["CMD.CHAT.HELP.PERMISSION.MODERATOR"] = "\n[#00FF00]/chat moder[/#] - moderator mode",
1205 ["CMD.MUTE.ALL.HELP"] = "\n[#00FF00]/muteall[/#] - Toggle global chat mute",
1206 ["NO.AVAILABLE.PREFIXS"] = "You have no prefixes available",
1207 ["PREFIX.NOT.FOUND"] = "Prefix \"{0}\" not found",
1208 ["PREFIX.CHANGED"] = "Prefix changed to {0}",
1209 ["AVAILABLE.COLORS.NAME"] = "Available name colors:\n{0}",
1210 ["AVAILABLE.COLORS.PREFIX"] = "Available prefixes:\n{0}",
1211 ["AVAILABLE.COLORS.MESSAGE"] = "Available chat colors:\n{0}",
1212 ["NO.AVAILABLE.COLORS"] = "You have no colors available",
1213 ["COLOR.NOT.FOUND"] = "Color \"{0}\" not found",
1214 ["NAME.COLOR.CHANGED"] = "Name color changed to {0}",
1215 ["MESSAGE.COLOR.CHANGED"] = "Message color changed to {0}",
1216 ["CMD.CHAT.SOUND.HELP"] = "Use [#00FF00]/chat sound[/#] [#008000]on[/#] or [#00FF00]/chat sound[/#] [#FF4500]off[/#] to toggle sound of income PM",
1217 ["SOUND.ENABLED"] = "You have turn income PM sounds [#008000]ON[/#]",
1218 ["SOUND.DISABLED"] = "You have turn income PM sounds [#FF4500]OFF[/#]",
1219 ["CMD.MUTE.HELP"] = "Use [#00FF00]/mute[/#] <\"player name\"> [time] [reason] to mute player",
1220 ["USER.ALREADY.MUTED"] = "Player \"{0}\" Already muted.\nReason: {1}\nTimeleft: {2}",
1221 ["USER.MUTED.REASON"] = "{0} has mute player \"{1}\"\nReason: {2}\nTimeleft: {3}",
1222 ["USER.MUTED.LOG"] = "\"{0}\" muted player \"{1}\" for {2}\nReason: \"{3}\"",
1223 ["CMD.UNMUTE.HELP"] = "Use [#00FF00]/unmute[/#] \"player name\" to unmute player",
1224 ["USER.UNMUTED"] = "{0} remove mute from player \"{1}\"",
1225 ["USER.UNMUTED.LOG"] = "\"{0}\" unmuted player \"{1}\"",
1226 ["YOU.MUTED"] = "You are muted, and may not chat!\nInitiator: {0}\nReason: {1}\nTimeleft: {2}",
1227 ["MUTE.ALL.ENABLED"] = "Global chat [#62ff29]ENABLED[/#]",
1228 ["MUTE.ALL.DISABLED"] = "Global chat [#ff552a]DISABLED[/#]",
1229 ["CMD.CHAT.IGNORE.HELP"] = "Commands list:\n[#00FF00]/chat ignore add[/#] \"player name\" - add player to your blacklist\n[#00FF00]/chat ignore remove[/#] \"player name\" - remove player from your blacklist\n[#00FF00]/chat ignore list[/#] - show your blacklist",
1230 ["USER.IS.IGNORE.LIST"] = "Player \"{0}\" already blacklisted",
1231 ["NOT.ON.IGNORE.LIST"] = "Player \"{0}\" isn't blacklisted",
1232 ["USER.ADD.IGNORE.LIST"] = "You successfully add player \"{0}\" to your blacklist",
1233 ["YOU.ADD.IGNORE.LIST"] = "Player \"{0}\" added you to his/her blacklist",
1234 ["IGNORE.LIST.IS.EMPTY"] = "Blacklist is empty",
1235 ["USER.REMOVE.IGNORE.LIST"] = "You have removed player \"{0}\" from your blacklist",
1236 ["YOU.REMOVE.IGNORE.LIST"] = "Player \"{0}\" removed you from his/her blacklist",
1237 ["IGNORE.LIST"] = "BLACKLIST:\n",
1238 ["CMD.PM.HELP"] = "Use [#00FF00]/pm[/#] \"player name\" \"message\" to send PM to another player",
1239 ["PM.SENDER.FORMAT"] = "[#e664a5]PM for {0}[/#]: {1}",
1240 ["PM.RECEIVER.FORMAT"] = "[#e664a5]PM from {0}[/#]: {1}",
1241 ["PM.NO.MESSAGES"] = "You havn't recive PM yet.",
1242 ["PM.PLAYER.LEAVE"] = "Player with who you were chating has left the server.",
1243 ["PM.YOU.ARE.BLACK.LIST"] = "You can't send PM to the player \"{0}\", you are in his/her blacklist",
1244 ["CMD.R.HELP"] = "Use [#00FF00]/r[/#] \"message\" to reply to the lates PM",
1245 ["CENSOR.ENABLED"] = "You have [#62ff29]ENABLE[/#] chat censority",
1246 ["CENSOR.DISABLED"] = "You have [#ff552a]DISABLE[/#] chat censority",
1247 ["NO.ACCESS"] = "You have no access to this command",
1248 ["PLAYER.NOT.FOUND"] = "PLayer \"{0}\" not found",
1249 ["MULTIPLE.PLAYERS.FOUND"] = "Multiply players found:\n{0}",
1250 ["PM.SELF"] = "You can't send messages to self",
1251 ["MODERATOR.ENABLE"] = "Moderator mode has been [#62ff29]ENABLED[/#]",
1252 ["MODERATOR.DISABLE"] = "Moderator mode has been [#ff552a]DISABLED[/#]",
1253 ["ADMIN.ENABLE"] = "Administrator mode has been [#62ff29]ENABLED[/#]",
1254 ["ADMIN.DISABLE"] = "Administrator mode has been [#ff552a]DISABLED[/#]",
1255 ["PLAYER.NOT.MUTED"] = "Player is not muted",
1256 ["RESET.SUCCESSFULL"] = "Your chat setting was resetted to default",
1257 ["CHAT.SPAM"] = "Your message is to loong!",
1258 ["CHAT.TOOMUCH"] = "Too long message. > 500",
1259 ["CMD.HELP.PREFIX"] = "Incorrect syntax! chatplus.prefix steamid/nick privilege",
1260 ["CMD.HELP.NAME"] = "Incorrect syntax! chatplus.name steamid/nick privilege",
1261 ["CMD.HELP.MESSAGE"] = "Incorrect syntax! chatplus.message steamid/nick privilege",
1262 ["NO.PERMISSION.PLAYER"] = "Player doesn't have requiered permission!",
1263 ["NO.PERMISSION.YOU"] = "You don't have requiered permission!",
1264 ["MUTE.EXPIRED"] = "Player {0} is no longer muted.",
1265 ["MUTE.LIST.HEAD"] = "Mutelist:",
1266 ["MUTE.LIST.BODY"] = "--------------------\nInitiator: {0}\nPlayer: {1}\nReason: {2}\nTimeleft: {3}\n--------------------",
1267 ["MUTE.LIST.NOONE"] = "No one is currently muted",
1268 ["PM.LOG"] = "PM from \"{0}\" to \"{1}\": {2}"
1269 }, this);
1270
1271 lang.RegisterMessages(new Dictionary<string, string>()
1272 {
1273 ["CMD.CHAT.HELP"] = "Доступные команды:\n[#00FF00]/chat censor[/#] - цензура в чате\n[#00FF00]/chat prefix[/#] - доступные префиксы\n[#00FF00]/chat name[/#] - доступные цвета имени\n[#00FF00]/chat message[/#] - доступные цвета сообщений\n[#00FF00]/chat ignore[/#] [#42f4ee]add/remove/list[/#] - управление чёрным списком\n[#00FF00]/chat sound[/#] [#42f4ee]on/off[/#] - звук при получении ЛС\n[#00FF00]/chat reset[/#] - Сбрасывает ваши настройки чата на стандартные.",
1274 ["CMD.CHAT.HELP.PERMISSION.ADMIN"] = "\n[#00FF00]/chat admin[/#] - режим администратора",
1275 ["CMD.CHAT.HELP.PERMISSION.MODERATOR"] = "\n[#00FF00]/chat moder[/#] - режим модератора",
1276 ["CMD.MUTE.ALL.HELP"] = "\n[#00FF00]/muteall[/#] - Блокировка/разблокировка общего чата",
1277 ["NO.AVAILABLE.PREFIXS"] = "У вас нет доступных префиксов",
1278 ["PREFIX.NOT.FOUND"] = "Префикс с названием \"{0}\" не найден",
1279 ["PREFIX.CHANGED"] = "Префикс изменен на {0}",
1280 ["AVAILABLE.COLORS.NAME"] = "Доступные цвета имени:\n{0}",
1281 ["AVAILABLE.COLORS.PREFIX"] = "Доступные префиксы:\n{0}",
1282 ["AVAILABLE.COLORS.MESSAGE"] = "Доступные цвета сообщений:\n{0}",
1283 ["NO.AVAILABLE.COLORS"] = "У вас нет доступных цветов",
1284 ["COLOR.NOT.FOUND"] = "Цвет с названием \"{0}\" не найден",
1285 ["NAME.COLOR.CHANGED"] = "Цвет имени успешно изменен на {0}",
1286 ["MESSAGE.COLOR.CHANGED"] = "Цвет сообщений успешно изменен на {0}",
1287 ["CMD.CHAT.SOUND.HELP"] = "Используйте [#00FF00]/chat sound[/#] [#008000]on[/#] или [#FF4500]off[/#] чтобы включить или выключить звуковое оповещение при получении ЛС",
1288 ["SOUND.ENABLED"] = "Вы включили звуковое оповещение при получении ЛС",
1289 ["SOUND.DISABLED"] = "Вы выключили звуковое оповещение при получении ЛС",
1290 ["CMD.MUTE.HELP"] = "Используйте [#00FF00]/mute[/#] <\"имя игрока\"> [длительность] [причина] чтобы заблокировать чат игроку",
1291 ["USER.ALREADY.MUTED"] = "У игрока \"{0}\" уже отключён чат.\nПричина: {1}\nОсталось времени: {2}",
1292 ["USER.MUTED.REASON"] = "{0} заблокировал чат игроку \"{1}\"\nПричина: {2}\nВремя блокировки: {3}",
1293 ["USER.MUTED.LOG"] = "\"{0}\" заблокировал чат игроку \"{1}\" на {2}\nПричина: \"{3}\"",
1294 ["CMD.UNMUTE.HELP"] = "Используйте [#00FF00]/unmute[/#] \"имя игрока\" чтобы разблокировать чат игроку",
1295 ["USER.UNMUTED"] = "{0} снял мут с игрока \"{1}\"",
1296 ["USER.UNMUTED.LOG"] = "\"{0}\" разблокировал чат \"{1}\"",
1297 ["YOU.MUTED"] = "Ваш чат заблокирован!\nЗаблокировавший: {0}\nПричина: {1}\nОсталось времени: {2}",
1298 ["MUTE.ALL.ENABLED"] = "Общий чат [#62ff29]РАЗБЛОКИРОВАН[/#]",
1299 ["MUTE.ALL.DISABLED"] = "Общий чат [#ff552a]ЗАБЛОКИРОВАН[/#]",
1300 ["CMD.CHAT.IGNORE.HELP"] = "Список команд:\n[#00FF00]/chat ignore add[/#] \"имя игрока\" - добавить в черный список\n[#00FF00]/chat ignore remove[/#] \"имя игрока\" - удалить из черного списка\n[#00FF00]/chat ignore list[/#] - показать черный список",
1301 ["USER.IS.IGNORE.LIST"] = "Игрок \"{0}\" уже находится в черном списке",
1302 ["USER.ADD.IGNORE.LIST"] = "Вы добавили игрока \"{0}\" в черный список",
1303 ["YOU.ADD.IGNORE.LIST"] = "Игрок \"{0}\" добавил вас в черный список",
1304 ["NOT.ON.IGNORE.LIST"] = "Игрок \"{0}\" не находится в чёрном списке",
1305 ["IGNORE.LIST.IS.EMPTY"] = "Черный список пуст",
1306 ["USER.REMOVE.IGNORE.LIST"] = "Вы удалили игрока \"{0}\" из черного списка",
1307 ["YOU.REMOVE.IGNORE.LIST"] = "Игрок \"{0}\" удалил вас из черного списка",
1308 ["IGNORE.LIST"] = "Чёрный список:\n",
1309 ["CMD.PM.HELP"] = "Используйте [#00FF00]/pm[/#] \"имя игрока\" \"сообщение\" чтобы отправить ЛС игроку",
1310 ["PM.SENDER.FORMAT"] = "[#e664a5]ЛС для {0}[/#]: {1}",
1311 ["PM.RECEIVER.FORMAT"] = "[#e664a5]ЛС от {0}[/#]: {1}",
1312 ["PM.NO.MESSAGES"] = "Вы не получали личных сообщений",
1313 ["PM.PLAYER.LEAVE"] = "Игрок с которым вы переписывались вышел с сервера",
1314 ["PM.YOU.ARE.BLACK.LIST"] = "Вы не можете отправить ЛС игроку \"{0}\", он добавил вас в черный список",
1315 ["CMD.R.HELP"] = "Используйте [#00FF00]/r[/#] \"сообщение\" чтобы ответить но последнее ЛС",
1316 ["CENSOR.ENABLED"] = "Вы [#62ff29]ВКЛЮЧИЛИ[/#] цензуру в чате",
1317 ["CENSOR.DISABLED"] = "Вы [#ff552a]ВЫКЛЮЧИЛИ[/#] цензуру в чате",
1318 ["NO.ACCESS"] = "У вас нет доступа к этой команде",
1319 ["PLAYER.NOT.FOUND"] = "Игрок \"{0}\" не найден",
1320 ["MULTIPLE.PLAYERS.FOUND"] = "Найдено несколько игроков с похожим именем:\n{0}",
1321 ["PM.SELF"] = "Вы не можете отправлять сообщения самому себе",
1322 ["MODERATOR.ENABLE"] = "Режим модератора [#62ff29]ВКЛЮЧЕН[/#]",
1323 ["MODERATOR.DISABLE"] = "Режим модератора [#ff552a]ВЫКЛЮЧЕН[/#]",
1324 ["ADMIN.ENABLE"] = "Режим администратора [#62ff29]ВКЛЮЧЕН[/#]",
1325 ["ADMIN.DISABLE"] = "Режим администратора [#ff552a]ВЫКЛЮЧЕН[/#]",
1326 ["PLAYER.NOT.MUTED"] = "У игрока не отключен чат",
1327 ["RESET.SUCCESSFULL"] = "Вы сбросили свои настройки чата на стандартные",
1328 ["CHAT.SPAM"] = "Ваше сообщение слишком длинное!",
1329 ["CHAT.TOOMUCH"] = "Слишком длинное сообщение. Больше 500 символов.",
1330 ["CMD.HELP.PREFIX"] = "Неверный синтаксис! chatplus.prefix steamid/ник привилегия",
1331 ["CMD.HELP.NAME"] = "Неверный синтаксис! chatplus.name steamid/ник привилегия",
1332 ["CMD.HELP.MESSAGE"] = "Неверный синтаксис! chatplus.message steamid/ник привилегия",
1333 ["NO.PERMISSION.PLAYER"] = "У игрока нет необходимой привилегии!",
1334 ["NO.PERMISSION.YOU"] = "У вас нет необходимой привилегии!",
1335 ["MUTE.EXPIRED"] = "Игроку \"{0}\" вновь доступен чат.",
1336 ["MUTE.LIST.HEAD"] = "Список игроков с отключённым чатом:",
1337 ["MUTE.LIST.BODY"] = "--------------------\nИнициатор: {0}\nИгрок: {1}\nПричина: {2}\nСрок: {3}\n--------------------",
1338 ["MUTE.LIST.NOONE"] = "Чат на данный момент доступен всем игрокам.",
1339 ["PM.LOG"] = "ЛС от \"{0}\" для \"{1}\": {2}"
1340 }, this, "ru");
1341 }
1342 #endregion
1343
1344 #region Config Initialization
1345 protected override void LoadDefaultConfig()
1346 {
1347 PrintWarning("Благодарим за приобритение плагина на сайте RustPlugin.ru. Если вы приобрели этот плагин на другом ресурсе знайте - это лишает вас гарантированных обновлений!");
1348 config = new ChatConfig()
1349 {
1350 CapsBlock = true,
1351 BadWordsBlock = false,
1352 MuteReasonAutoMute = "Нецензурная лексика",
1353 MuteReason = "Не указана",
1354 MuteBadWordsDefault = 300,
1355 PrivateSoundMessage = true,
1356 PrivateSoundMessagePath = "assets/bundled/prefabs/fx/notice/stack.world.fx.prefab",
1357 adminPrivilages = new AdminPrivilages
1358 {
1359 AdminPermiss = "chatplus.adminmode",
1360 ModerPermiss = "chatplus.moderatormode",
1361 MutePermiss = "chatplus.mute",
1362 UnMutePermiss = "chatplus.unmute",
1363 MuteAllPermiss = "chatplus.muteall",
1364 AssignPermiss = "chatplus.assign",
1365 AdminFormat = "[#a5e664]Администратор[/#]: {0}",
1366 ModerFormat = "[#a5e664]Модератор[/#]: {0}",
1367 HideAdmins = false,
1368 AdminReplace = "Модератор чата"
1369 },
1370 prefixes = new List<ChatPrivilege>()
1371 {
1372 new ChatPrivilege()
1373 {
1374 Perm = "chatplus.default",
1375 Arg = "default",
1376 Format = "",
1377 },
1378 new ChatPrivilege()
1379 {
1380 Perm = "chatplus.vip",
1381 Arg = "vip",
1382 Format = "[#9370DB][VIP][/#]",
1383 },
1384 new ChatPrivilege()
1385 {
1386 Perm = "chatplus.premium",
1387 Arg = "premium",
1388 Format = "[#00FF7F][Премиум][/#]",
1389 }
1390 },
1391 names = new List<ChatPrivilege>()
1392 {
1393 new ChatPrivilege()
1394 {
1395 Perm = "chatplus.default",
1396 Arg = "default",
1397 Format = "[#ffffff]{0}[/#]",
1398 },
1399 new ChatPrivilege()
1400 {
1401 Perm = "chatplus.hotpink",
1402 Arg = "hotpink",
1403 Format = "[#FF69B4]{0}[/#]",
1404 },
1405 new ChatPrivilege()
1406 {
1407 Perm = "chatplus.tomato",
1408 Arg = "tomato",
1409 Format = "[#FF6347]{0}[/#]",
1410 }
1411 },
1412 messages = new List<ChatPrivilege>()
1413 {
1414 new ChatPrivilege()
1415 {
1416 Perm = "chatplus.default",
1417 Arg = "default",
1418 Format = "[#ffffff]{0}[/#]",
1419 },
1420 new ChatPrivilege()
1421 {
1422 Perm = "chatplus.blue",
1423 Arg = "blue",
1424 Format = "[#64a5e6]{0}[/#]",
1425 },
1426 new ChatPrivilege()
1427 {
1428 Perm = "chatplus.gold",
1429 Arg = "gold",
1430 Format = "[#DAA520]{0}[/#]",
1431 }
1432 },
1433 badWords = new Dictionary<string, List<string>>()
1434 {
1435 { "ебля", new List<string>() },
1436 { "сука", new List<string>() },
1437 { "пидор", new List<string>() },
1438 },
1439 ConsoleName = "Server Console",
1440 ConsoleFormat = "[+16][#00ff00]{0}[/#]: {1}[/+]",
1441 PMAva = true
1442 };
1443 }
1444 protected override void LoadConfig()
1445 {
1446 base.LoadConfig();
1447 {
1448 config = Config.ReadObject<ChatConfig>();
1449 if (!config.names.Any(c => c.Perm == "chatplus.default"))
1450 {
1451 PrintWarning("Не удаляйте привилегию chatplus.default! Стандартное имя восстановлено. Без него плагин работать не будет.");
1452 config.names.Add(new ChatPrivilege()
1453 {
1454 Arg = "default",
1455 Perm = "chatplus.default",
1456 Format = "<color=#ffffff>{0}</color>"
1457 });
1458 Config.WriteObject(config);
1459 }
1460 if (!config.messages.Any(c => c.Perm == "chatplus.default"))
1461 {
1462 PrintWarning("Не удаляйте привилегию chatplus.default! Стандартный вид сообщений восстановлен. Без него плагин работать не будет.");
1463 config.messages.Add(new ChatPrivilege()
1464 {
1465 Arg = "default",
1466 Perm = "chatplus.default",
1467 Format = "<color=#ffffff>{0}</color>"
1468 });
1469 Config.WriteObject(config);
1470 }
1471 if (!config.prefixes.Any(c => c.Perm == "chatplus.default"))
1472 {
1473 PrintWarning("Не удаляйте привилегию chatplus.default! Стандартный перфикс восстановлен. Без него плагин работать не будет.");
1474 config.prefixes.Add(new ChatPrivilege()
1475 {
1476 Arg = "default",
1477 Perm = "chatplus.default",
1478 Format = ""
1479 });
1480 Config.WriteObject(config);
1481 }
1482 //Для совместимости с прошлыми версиями
1483 bool changed = false;
1484 if (config.ConsoleName == null)
1485 {
1486 PrintWarning("В файл конфигурации добавлен новый параметр - \"M. Имя консоли при отправке личных сообщений и отключении чата из консоли\"");
1487 config.ConsoleName = "Server Console";
1488 changed = true;
1489 }
1490 if (config.ConsoleFormat == null)
1491 {
1492 PrintWarning("В файл конфигурации добавлен новый параметр - \"N. Формат отправки сообщений из консоли командой say\"");
1493 config.ConsoleFormat = "[+16][#00ff00]{0}[/#]: {1}[/+]";
1494 changed = true;
1495 }
1496 if (!config.PMAva.HasValue)
1497 {
1498 PrintWarning("В файл конфигурации добавлен новый параметр - \"O. Отображать ли аватарки игроков при получении ЛС(только RUST)\"");
1499 config.PMAva = true;
1500 changed = true;
1501 }
1502 if (!config.adminPrivilages.HideAdmins.HasValue)
1503 {
1504 PrintWarning("В файл конфигурации добавлен новый параметр - \"H - Скрывать имена администраторов при блокировке чата\"");
1505 config.adminPrivilages.HideAdmins = false;
1506 changed = true;
1507 }
1508 if(config.adminPrivilages.AdminReplace == null)
1509 {
1510 PrintWarning("В файл конфигурации добавлен новый параметр - \"H - Замена имени администратора при блокировке чата(если включено)\"");
1511 config.adminPrivilages.AdminReplace = "Модератор чата";
1512 changed = true;
1513 }
1514 if (changed)
1515 SaveConfig();
1516 }
1517 }
1518 protected override void SaveConfig()
1519 {
1520 Config.WriteObject(config);
1521 }
1522 #endregion
1523
1524 #region Configuration
1525 public class ChatPrivilege
1526 {
1527 [JsonProperty("Привилегия")]
1528 public string Perm;
1529 [JsonProperty("Аргумент")]
1530 public string Arg;
1531 [JsonProperty("Формат")]
1532 public string Format;
1533 }
1534 public class AdminPrivilages
1535 {
1536 [JsonProperty("Привилегия для включения режима администратора")]
1537 public string AdminPermiss;
1538 [JsonProperty("Привилегия для включения режима модератора")]
1539 public string ModerPermiss;
1540 [JsonProperty("Привилегия для использования команды /mute")]
1541 public string MutePermiss;
1542 [JsonProperty("Привилегия для использования команды /unmute")]
1543 public string UnMutePermiss;
1544 [JsonProperty("Формат чата режима администратор")]
1545 public string AdminFormat;
1546 [JsonProperty("Формат чата режима модератор")]
1547 public string ModerFormat;
1548 [JsonProperty("Привилегия для полного отключения чата")]
1549 public string MuteAllPermiss;
1550 [JsonProperty("Привилегия для использования консольных команд на присваивание префикса и цветов")]
1551 public string AssignPermiss;
1552 [JsonProperty("Скрывать имена администраторов при блокировке чата")]
1553 public bool? HideAdmins;
1554 [JsonProperty("Замена имени администратора при блокировке чата(если включено)")]
1555 public string AdminReplace;
1556 }
1557 public class ChatConfig
1558 {
1559 [JsonProperty("A. Автоматически блокировать чат за нецензурную лексику")]
1560 public bool BadWordsBlock;
1561 [JsonProperty("B. Длительность блокировки чата за нецензурную лексику(в секундах)")]
1562 public int MuteBadWordsDefault;
1563 [JsonProperty("C. Причина мута при автоматической блокировке чата за нецензурную лексику")]
1564 public string MuteReasonAutoMute;
1565 [JsonProperty("D. Стандартная причина мута")]
1566 public string MuteReason;
1567 [JsonProperty("E. Воспроизводить звук при получении личного сообщения")]
1568 public bool PrivateSoundMessage;
1569 [JsonProperty("F. Полный путь к звуковому файлу")]
1570 public string PrivateSoundMessagePath;
1571 [JsonProperty("G. Выключить заглавные буквы в чате")]
1572 public bool CapsBlock;
1573 [JsonProperty("H. Настройки привелегий администраторов")]
1574 public AdminPrivilages adminPrivilages;
1575 [JsonProperty("I. Цвет имен")]
1576 public List<ChatPrivilege> names;
1577 [JsonProperty("J. Префиксы")]
1578 public List<ChatPrivilege> prefixes;
1579 [JsonProperty("K. Цвет сообщений")]
1580 public List<ChatPrivilege> messages;
1581 [JsonProperty("L. Список начальных букв нецензурных слов или слова целиком | список исключений")]
1582 public Dictionary<string, List<string>> badWords;
1583 [JsonProperty("M. Имя консоли при отправке личных сообщений и отключении чата из консоли")]
1584 public string ConsoleName;
1585 [JsonProperty("N. Формат отправки сообщений из консоли командой say")]
1586 public string ConsoleFormat;
1587 [JsonProperty("O. Отображать ли аватарки игроков при получении ЛС(только RUST)")]
1588 public bool? PMAva;
1589 public void RegisterPerms()
1590 {
1591 PermissionService.RegisterPermissions(prefixes.Select(p => p.Perm).ToList());
1592 PermissionService.RegisterPermissions(names.Select(p => p.Perm).ToList());
1593 PermissionService.RegisterPermissions(messages.Select(p => p.Perm).ToList());
1594 PermissionService.RegisterPermissions(new List<string>()
1595 {
1596 adminPrivilages.AdminPermiss,
1597 adminPrivilages.ModerPermiss,
1598 adminPrivilages.MutePermiss,
1599 adminPrivilages.MuteAllPermiss,
1600 adminPrivilages.AssignPermiss,
1601 adminPrivilages.UnMutePermiss
1602 });
1603 }
1604
1605 public ChatPrivilege Get(List<ChatPrivilege> list, string perm)
1606 {
1607 return list.FirstOrDefault(p => p.Perm == perm);
1608 }
1609 }
1610 #endregion
1611
1612 #region API
1613 bool IsPlayerMuted(object id) => MuteData.IsMuted(id.ToString());
1614 void OnPluginUnloaded(Plugin plugin)
1615 {
1616 if (ThirdPartyTitles.ContainsKey(plugin))
1617 ThirdPartyTitles.Remove(plugin);
1618 }
1619 private void API_RegisterThirdPartyTitle(Plugin plugin, Func<IPlayer, string> titleGetter) => ThirdPartyTitles[plugin] = titleGetter;
1620 #endregion
1621
1622 #region PermissionService
1623
1624 public static class PermissionService
1625 {
1626 public static Permission permission = Interface.GetMod().GetLibrary<Permission>();
1627
1628 public static bool HasPermission(string uid, string permissionName)
1629 {
1630 return !string.IsNullOrEmpty(permissionName) && permission.UserHasPermission(uid, permissionName);
1631 }
1632
1633 public static void RegisterPermissions(List<string> permissions)
1634 {
1635 if (permissions == null) throw new ArgumentNullException("commands");
1636
1637 foreach (var permissionName in permissions.Where(permissionName => !permission.PermissionExists(permissionName)))
1638 {
1639 permission.RegisterPermission(permissionName, m_Instance);
1640 }
1641 }
1642 public static bool UserIDVaild(string userID)
1643 {
1644 return permission.UserIdValid(userID);
1645 }
1646 }
1647
1648 #endregion
1649 }
1650}
1651///////////////////////////////////////////////