using Newtonsoft.Json; using Oxide.Core; using Oxide.Core.Plugins; using Oxide.Game.Rust.Cui; using UnityEngine; using System.Globalization; using System.Collections; using System.Collections.Generic; using System.Linq; using System; using Oxide.Game.Rust.Libraries; namespace Oxide.Plugins { [Info("RustApp Lite", "RustApp", "1.0.7")] [Description("Get reports on players in Discord, using a nicely designed interface or F7")] public class RustAppLite : RustPlugin { #region Configuration private class Configuration { [JsonProperty("[UI] Chat commands")] public List report_ui_commands = new List(); [JsonProperty("[UI] Report reasons")] public List report_ui_reasons = new List(); [JsonProperty("[UI] Cooldown between reports (seconds)")] public int report_ui_cooldown = 300; [JsonProperty("[UI] Auto-parse reports from F7 (ingame reports)")] public bool report_ui_auto_parse = true; [JsonProperty("[Discord] Webhook to send reports")] public string discord_webhook = ""; [JsonProperty("[Discord-Translations] Nickname field")] public string discord_translations_nickname = "Nickname"; [JsonProperty("[Discord-Translations] Reason field")] public string discord_translations_reason = "Reason"; [JsonProperty("[Discord-Translations] Comment field")] public string discord_translations_comment = "Comment"; [JsonProperty("[Discord-Translations] Report sent text")] public string discord_translations_report_sent = "Report sent"; public static Configuration Generate() { return new Configuration { report_ui_commands = new List { "report", "reports" }, report_ui_reasons = new List { "Cheat", "Abusive", "Spam" }, report_ui_cooldown = 300, report_ui_auto_parse = true, discord_webhook = "", discord_translations_comment = "Comment", discord_translations_nickname = "Nickname", discord_translations_reason = "Reason", discord_translations_report_sent = "Report sent" }; } } protected override void LoadConfig() { base.LoadConfig(); try { _Settings = Config.ReadObject(); } catch { PrintWarning($"Error reading config, creating one new config!"); LoadDefaultConfig(); } SaveConfig(); } protected override void LoadDefaultConfig() => _Settings = Configuration.Generate(); protected override void SaveConfig() => Config.WriteObject(_Settings); #endregion #region DiscordEmbedMessage public class DiscordMessage { public string content { get; set; } public DiscordEmbed[] embeds { get; set; } public DiscordMessage(string Content, DiscordEmbed[] Embeds = null) { content = Content; embeds = Embeds; } public void Send(string url) { _RustAppLite.webrequest.Enqueue(url, JsonConvert.SerializeObject(this), (code, response) => { if (code == 200) { return; } _RustAppLite.Error( $"Веб-хук не был отправлен ({response})", $"Webhook was not sent ({response})" ); }, _RustAppLite, Core.Libraries.RequestMethod.POST, _Headeers, 30f); } public static Dictionary _Headeers = new Dictionary { ["Content-Type"] = "application/json" }; } public class DiscordEmbed { public string title { get; set; } public string description { get; set; } public int? color { get; set; } public DiscordField[] fields { get; set; } public DiscordFooter footer { get; set; } public DiscordAuthor author { get; set; } public DiscordEmbed(string Title, string Description, int? Color = null, DiscordField[] Fields = null, DiscordFooter Footer = null, DiscordAuthor Author = null) { title = Title; description = Description; color = Color; fields = Fields; footer = Footer; author = Author; } } public class DiscordFooter { public string text { get; set; } public string icon_url { get; set; } public string proxy_icon_url { get; set; } public DiscordFooter(string Text, string Icon_url, string Proxy_icon_url = null) { text = Text; icon_url = Icon_url; proxy_icon_url = Proxy_icon_url; } } public class DiscordAuthor { public string name { get; set; } public string url { get; set; } public string icon_url { get; set; } public string proxy_icon_url { get; set; } public DiscordAuthor(string Name, string Url, string Icon_url, string Proxy_icon_url = null) { name = Name; url = Url; icon_url = Icon_url; proxy_icon_url = Proxy_icon_url; } } public class DiscordField { public string name { get; set; } public string value { get; set; } public bool inline { get; set; } public DiscordField(string Name, string Value, bool Inline = false) { name = Name; value = Value; inline = Inline; } } #endregion DiscordEmbedMessage #region Interfaces private static string ReportLayer = "RAL_CommandHandlerUI"; private void DrawReportInterface(BasePlayer player, int page = 0, string search = "", bool redraw = false, BasePlayer preselect = null) { var lineAmount = 6; var lineMargin = 8; var size = (float)(700 - lineMargin * lineAmount) / lineAmount; var list = new List(); if (preselect != null) { list.Add(preselect); } list.AddRange(BasePlayer.activePlayerList.ToList().Where(v => v.userID != preselect?.userID)); var finalList = list .FindAll(v => v.displayName.ToLower().Contains(search) || v.UserIDString.ToLower().Contains(search) || search == null) .Skip(page * 18) .Take(18); if (finalList.Count() == 0) { if (search == null) { DrawReportInterface(player, page - 1); return; } } CuiElementContainer container = new CuiElementContainer(); if (!redraw) { container.Add(new CuiPanel { CursorEnabled = true, RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1", OffsetMax = "0 0" }, Image = { Color = "0 0 0 0.8", Material = "assets/content/ui/uibackgroundblur-ingamemenu.mat" } }, "Overlay", ReportLayer, ReportLayer); container.Add(new CuiButton() { RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1", OffsetMax = "0 0" }, Button = { Color = HexToRustFormat("#343434"), Sprite = "assets/content/ui/ui.background.transparent.radial.psd", Close = ReportLayer }, Text = { Text = "" } }, ReportLayer); } container.Add(new CuiPanel { RectTransform = { AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = "-368 -200", OffsetMax = "368 142" }, Image = { Color = "1 0 0 0" } }, ReportLayer, ReportLayer + ".C", ReportLayer + ".C"); container.Add(new CuiPanel { RectTransform = { AnchorMin = "1 0", AnchorMax = "1 1", OffsetMin = "-36 0", OffsetMax = "0 0" }, Image = { Color = "0 0 1 0" } }, ReportLayer + ".C", ReportLayer + ".R"); //↓ ↑ container.Add(new CuiButton() { RectTransform = { AnchorMin = "0 0", AnchorMax = "1 0.5", OffsetMin = "0 0", OffsetMax = "0 -4" }, Button = { Color = HexToRustFormat($"#{(list.Count > 18 && finalList.Count() == 18 ? "D0C6BD4D" : "D0C6BD33")}"), Command = list.Count > 18 && finalList.Count() == 18 ? $"RAL_CommandHandler search {page + 1}" : "" }, Text = { Text = "↓", Align = TextAnchor.MiddleCenter, Font = "robotocondensed-bold.ttf", FontSize = 24, Color = HexToRustFormat($"{(list.Count > 18 && finalList.Count() == 18 ? "D0C6BD" : "D0C6BD4D")}") } }, ReportLayer + ".R", ReportLayer + ".RD"); container.Add(new CuiButton() { RectTransform = { AnchorMin = "0 0.5", AnchorMax = "1 1", OffsetMin = "0 4", OffsetMax = "0 0" }, Button = { Color = HexToRustFormat($"#{(page == 0 ? "D0C6BD33" : "D0C6BD4D")}"), Command = page == 0 ? "" : $"RAL_CommandHandler search {page - 1}" }, Text = { Text = "↑", Align = TextAnchor.MiddleCenter, Font = "robotocondensed-bold.ttf", FontSize = 24, Color = HexToRustFormat($"{(page == 0 ? "D0C6BD4D" : "D0C6BD")}") } }, ReportLayer + ".R", ReportLayer + ".RU"); container.Add(new CuiPanel { RectTransform = { AnchorMin = "1 1", AnchorMax = "1 1", OffsetMin = "-250 8", OffsetMax = "0 43" }, Image = { Color = HexToRustFormat("#D0C6BD33") } }, ReportLayer + ".C", ReportLayer + ".S"); container.Add(new CuiElement { Parent = ReportLayer + ".S", Components = { new CuiInputFieldComponent { Text = $"{lang.GetMessage("Header.Search.Placeholder", this, player.UserIDString)}", FontSize = 14, Font = "robotocondensed-regular.ttf", Color = HexToRustFormat("#D0C6BD80"), Align = TextAnchor.MiddleLeft, Command = "RAL_CommandHandler search 0", NeedsKeyboard = true}, new CuiRectTransformComponent { AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = "10 0", OffsetMax = "-85 0"} } }); container.Add(new CuiButton { RectTransform = { AnchorMin = "1 0", AnchorMax = "1 1", OffsetMin = "-75 0", OffsetMax = "0 0" }, Button = { Color = HexToRustFormat("#D0C6BD"), Material = "assets/icons/greyout.mat" }, Text = { Text = $"{lang.GetMessage("Header.Search", this, player.UserIDString)}", Font = "robotocondensed-bold.ttf", Color = HexToRustFormat("#443F3B"), FontSize = 14, Align = TextAnchor.MiddleCenter } }, ReportLayer + ".S", ReportLayer + ".SB"); container.Add(new CuiPanel { RectTransform = { AnchorMin = "0 1", AnchorMax = "0.5 1", OffsetMin = "0 7", OffsetMax = "0 47" }, Image = { Color = "0.8 0.8 0.8 0" } }, ReportLayer + ".C", ReportLayer + ".LT"); container.Add(new CuiLabel() { RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = "0 0", OffsetMax = "0 0" }, Text = { Text = $"{lang.GetMessage("Header.Find", this, player.UserIDString)} {(search != null && search.Length > 0 ? $"- {(search.Length > 20 ? search.Substring(0, 14).ToUpper() + "..." : search.ToUpper())}" : "")}", Font = "robotocondensed-bold.ttf", Color = HexToRustFormat("#D0C6BD"), FontSize = 24, Align = TextAnchor.UpperLeft } }, ReportLayer + ".LT"); container.Add(new CuiLabel() { RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = "0 0", OffsetMax = "0 0" }, Text = { Text = search == null || search.Length == 0 ? lang.GetMessage("Header.SubDefault", this, player.UserIDString) : finalList.Count() == 0 ? lang.GetMessage("Header.SubFindEmpty", this, player.UserIDString) : lang.GetMessage("Header.SubFindResults", this, player.UserIDString), Font = "robotocondensed-regular.ttf", Color = HexToRustFormat("#D0C6BD4D"), FontSize = 14, Align = TextAnchor.LowerLeft } }, ReportLayer + ".LT"); container.Add(new CuiPanel { RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = "0 0", OffsetMax = "-40 0" }, Image = { Color = "0 1 0 0" } }, ReportLayer + ".C", ReportLayer + ".L"); for (var y = 0; y < 3; y++) { for (var x = 0; x < 6; x++) { var target = finalList.ElementAtOrDefault(y * 6 + x); if (target) { container.Add(new CuiPanel { RectTransform = { AnchorMin = "0 1", AnchorMax = "0 1", OffsetMin = $"{x * size + lineMargin * x} -{(y + 1) * size + lineMargin * y}", OffsetMax = $"{(x + 1) * size + lineMargin * x} -{y * size + lineMargin * y}" }, Image = { Color = HexToRustFormat("#D0C6BD33") } }, ReportLayer + ".L", ReportLayer + $".{target.UserIDString}"); container.Add(new CuiElement { Parent = ReportLayer + $".{target.UserIDString}", Components = { new CuiRawImageComponent { SteamId = target.UserIDString, Sprite = "assets/icons/loading.png" }, new CuiRectTransformComponent { AnchorMin = "0 0", AnchorMax = "1 1", OffsetMax = "0 0" } } }); container.Add(new CuiPanel() { RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = "0 0", OffsetMax = "0 0" }, Image = { Sprite = "assets/content/ui/ui.background.transparent.linear.psd", Color = HexToRustFormat("#282828f2") } }, ReportLayer + $".{target.UserIDString}"); string normaliseName = NormalizeString(target.displayName); string name = normaliseName.Length > 14 ? normaliseName.Substring(0, 15) + ".." : normaliseName; container.Add(new CuiLabel { RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = "6 16", OffsetMax = "0 0" }, Text = { Text = name, Align = TextAnchor.LowerLeft, Font = "robotocondensed-bold.ttf", FontSize = 13, Color = HexToRustFormat("#D0C6BD") } }, ReportLayer + $".{target.UserIDString}"); container.Add(new CuiLabel { RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = "6 5", OffsetMax = "0 0" }, Text = { Text = target.UserIDString, Align = TextAnchor.LowerLeft, Font = "robotocondensed-regular.ttf", FontSize = 10, Color = HexToRustFormat("#D0C6BD80") } }, ReportLayer + $".{target.UserIDString}"); container.Add(new CuiButton() { RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = "0 0", OffsetMax = "0 0" }, Button = { Color = "0 0 0 0", Command = $"RAL_CommandHandler show {target.UserIDString} {x * size + lineMargin * x} -{(y + 1) * size + lineMargin * y} {(x + 1) * size + lineMargin * x} -{y * size + lineMargin * y} {x >= 3}" }, Text = { Text = "" } }, ReportLayer + $".{target.UserIDString}"); } else { container.Add(new CuiPanel { RectTransform = { AnchorMin = "0 1", AnchorMax = "0 1", OffsetMin = $"{x * size + lineMargin * x} -{(y + 1) * size + lineMargin * y}", OffsetMax = $"{(x + 1) * size + lineMargin * x} -{y * size + lineMargin * y}" }, Image = { Color = HexToRustFormat("#D0C6BD33") } }, ReportLayer + ".L"); } } } CuiHelper.AddUi(player, container); if (preselect != null) { player.SendConsoleCommand($"RAL_CommandHandler show {preselect.UserIDString} 0 -{size} {size} 0 false"); } } private static string HexToRustFormat(string hex) { if (string.IsNullOrEmpty(hex)) { hex = "#FFFFFFFF"; } var str = hex.Trim('#'); if (str.Length == 6) str += "FF"; if (str.Length != 8) { throw new Exception(hex); throw new InvalidOperationException("Cannot convert a wrong format."); } var r = byte.Parse(str.Substring(0, 2), NumberStyles.HexNumber); var g = byte.Parse(str.Substring(2, 2), NumberStyles.HexNumber); var b = byte.Parse(str.Substring(4, 2), NumberStyles.HexNumber); var a = byte.Parse(str.Substring(6, 2), NumberStyles.HexNumber); Color color = new Color32(r, g, b, a); return string.Format("{0:F2} {1:F2} {2:F2} {3:F2}", color.r, color.g, color.b, color.a); } #endregion #region Variables private static RustAppLite _RustAppLite; private static Configuration _Settings; private Dictionary _Cooldowns = new Dictionary(); #endregion #region Initialization private void OnServerInitialized() { _RustAppLite = this; if (_Settings.discord_webhook == null || _Settings.discord_webhook.Length < 5) { Error( "Установите discord_webhook в конфигурации плагина, и перезапустите плагин o.reload RustAppLite", "Setup discord_webhook in plugin config, then reload plugin o.reload RustAppLite" ); return; } _Settings.report_ui_commands.ForEach(v => { cmd.AddChatCommand(v, this, nameof(ChatCmdReport)); }); Log( "\nВы пользуетесь упрощённой версией плагина RustApp!\nВ полной версии есть:\n — статистика игрока\n — система вызова на проверку\n — бан система\n — история чата/команд\n — и многое другое на сайте: https://rustapp.io", "\nYou are using the simplified version of the RustApp plugin!\nThe full version includes:\n — player statistics\n — inspection system\n — ban system\n — chat/team history\n — and much more on the website: https://rustapp.io" ); if (!_Settings.report_ui_auto_parse) { Unsubscribe(nameof(OnPlayerReported)); } WriteLiteMarker(); } private void WriteLiteMarker() { if (Interface.Oxide.DataFileSystem.ExistsDatafile(Name)) { return; } // Is using in main plugin to detect users, who switched from Lite to main branch Interface.Oxide.DataFileSystem.WriteObject(Name, CurrentTime()); } protected override void LoadDefaultMessages() { lang.RegisterMessages(new Dictionary { ["Header.Find"] = "FIND PLAYER", ["Header.SubDefault"] = "Who do you want to report?", ["Header.SubFindResults"] = "Here are players, which we found", ["Header.SubFindEmpty"] = "No players was found", ["Header.Search"] = "Search", ["Header.Search.Placeholder"] = "Enter nickname/steamid", ["Subject.Head"] = "Select the reason for the report", ["Subject.SubHead"] = "For player %PLAYER%", ["Cooldown"] = "Wait %TIME% sec.", ["Sent"] = "Report succesful sent", ["Player.Not.Found"] = "Player with requested ID not found" }, this, "en"); lang.RegisterMessages(new Dictionary { ["Header.Find"] = "НАЙТИ ИГРОКА", ["Header.SubDefault"] = "На кого вы хотите пожаловаться?", ["Header.SubFindResults"] = "Вот игроки, которых мы нашли", ["Header.SubFindEmpty"] = "Игроки не найдены", ["Header.Search"] = "Поиск", ["Header.Search.Placeholder"] = "Введите ник/steamid", ["Subject.Head"] = "Выберите причину репорта", ["Subject.SubHead"] = "На игрока %PLAYER%", ["Cooldown"] = "Подожди %TIME% сек.", ["Sent"] = "Жалоба успешно отправлена", ["Player.Not.Found"] = "Игрок с указанным ID не найден" }, this, "ru"); } private void Unload() { foreach (var player in BasePlayer.activePlayerList) { CuiHelper.DestroyUi(player, ReportLayer); } _RustAppLite = null; _Settings = null; } #endregion #region Hooks private void OnPlayerReported(BasePlayer reporter, string targetName, string targetId, string subject, string message, string type) { // TODO: Unsubscribed, if _Settings.report_ui_auto_parse is setted to false var target = BasePlayer.Find(targetId) ?? BasePlayer.FindSleeping(targetId); if (target == null) { return; } RA_ReportSend(reporter.UserIDString, targetId, type, message); } #endregion #region Commands [ConsoleCommand("RAL_CommandHandler")] private void CmdConsoleReportPanel(ConsoleSystem.Arg args) { var player = args.Player(); if (player == null || !args.HasArgs(1)) { return; } switch (args.Args[0].ToLower()) { case "search": { int page = args.HasArgs(2) ? int.Parse(args.Args[1]) : 0; string search = args.HasArgs(3) ? args.Args[2] : ""; Effect effect = new Effect("assets/prefabs/tools/detonator/effects/unpress.prefab", player, 0, new Vector3(), new Vector3()); EffectNetwork.Send(effect, player.Connection); DrawReportInterface(player, page, search, true); break; } case "show": { string targetId = args.Args[1]; BasePlayer target = BasePlayer.Find(targetId) ?? BasePlayer.FindSleeping(targetId); Effect effect = new Effect("assets/prefabs/tools/detonator/effects/unpress.prefab", player, 0, new Vector3(), new Vector3()); EffectNetwork.Send(effect, player.Connection); CuiElementContainer container = new CuiElementContainer(); CuiHelper.DestroyUi(player, ReportLayer + $".T"); container.Add(new CuiPanel { RectTransform = { AnchorMin = "0 1", AnchorMax = "0 1", OffsetMin = $"{args.Args[2]} {args.Args[3]}", OffsetMax = $"{args.Args[4]} {args.Args[5]}" }, Image = { Color = "0 0 0 1" } }, ReportLayer + $".L", ReportLayer + $".T"); container.Add(new CuiButton() { RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = $"-500 -500", OffsetMax = $"500 500" }, Button = { Close = $"{ReportLayer}.T", Color = "0 0 0 1", Sprite = "assets/content/ui/ui.circlegradient.png" } }, ReportLayer + $".T"); bool leftAlign = bool.Parse(args.Args[6]); container.Add(new CuiButton() { RectTransform = { AnchorMin = $"{(leftAlign ? -1 : 2)} 0", AnchorMax = $"{(leftAlign ? -2 : 3)} 1", OffsetMin = $"-500 -500", OffsetMax = $"500 500" }, Button = { Close = $"{ReportLayer}.T", Color = HexToRustFormat("#343434"), Sprite = "assets/content/ui/ui.circlegradient.png" } }, ReportLayer + $".T"); container.Add(new CuiButton() { RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = $"-1111111 -1111111", OffsetMax = $"1111111 1111111" }, Button = { Close = $"{ReportLayer}.T", Color = "0 0 0 0.5", Material = "assets/content/ui/uibackgroundblur-ingamemenu.mat" } }, ReportLayer + $".T"); container.Add(new CuiLabel { RectTransform = { AnchorMin = $"{(leftAlign ? "0" : "1")} 0", AnchorMax = $"{(leftAlign ? "0" : "1")} 1", OffsetMin = $"{(leftAlign ? "-350" : "20")} 0", OffsetMax = $"{(leftAlign ? "-20" : "350")} -5" }, Text = { FadeIn = 0.4f, Text = lang.GetMessage("Subject.Head", this, player.UserIDString), Font = "robotocondensed-bold.ttf", Color = HexToRustFormat("#D0C6BD"), FontSize = 24, Align = leftAlign ? TextAnchor.UpperRight : TextAnchor.UpperLeft } }, ReportLayer + ".T"); container.Add(new CuiLabel { RectTransform = { AnchorMin = $"{(leftAlign ? "0" : "1")} 0", AnchorMax = $"{(leftAlign ? "0" : "1")} 1", OffsetMin = $"{(leftAlign ? "-250" : "20")} 0", OffsetMax = $"{(leftAlign ? "-20" : "250")} -35" }, Text = { FadeIn = 0.4f, Text = $"{lang.GetMessage("Subject.SubHead", this, player.UserIDString).Replace("%PLAYER%", $"{target.displayName}")}", Font = "robotocondensed-regular.ttf", Color = HexToRustFormat("#D0C6BD80"), FontSize = 14, Align = leftAlign ? TextAnchor.UpperRight : TextAnchor.UpperLeft } }, ReportLayer + ".T"); container.Add(new CuiElement { Parent = ReportLayer + $".T", Components = { new CuiRawImageComponent { SteamId = target.UserIDString, Sprite = "assets/icons/loading.png" }, new CuiRectTransformComponent { AnchorMin = "0 0", AnchorMax = "1 1", OffsetMax = "0 0" } } }); for (var i = 0; i < _Settings.report_ui_reasons.Count; i++) { var offXMin = (20 + (i * 5)) + i * 80; var offXMax = 20 + (i * 5) + (i + 1) * 80; container.Add(new CuiButton() { RectTransform = { AnchorMin = $"{(leftAlign ? 0 : 1)} 0", AnchorMax = $"{(leftAlign ? 0 : 1)} 0", OffsetMin = $"{(leftAlign ? -offXMax : offXMin)} 15", OffsetMax = $"{(leftAlign ? -offXMin : offXMax)} 45" }, Button = { FadeIn = 0.4f + i * 0.2f, Color = HexToRustFormat("#D0C6BD4D"), Command = $"RAL_CommandHandler report {target.UserIDString} {_Settings.report_ui_reasons[i].Replace(" ", "0")}" }, Text = { FadeIn = 0.4f + i * 0.2f, Text = $"{_Settings.report_ui_reasons[i]}", Align = TextAnchor.MiddleCenter, Color = HexToRustFormat("#D0C6BD"), Font = "robotocondensed-bold.ttf", FontSize = 16 } }, ReportLayer + $".T"); } CuiHelper.AddUi(player, container); break; } case "report": { if (!_Cooldowns.ContainsKey(player.userID)) { _Cooldowns.Add(player.userID, 0); } if (_Cooldowns[player.userID] > CurrentTime()) { var msg = lang.GetMessage("Cooldown", this, player.UserIDString).Replace("%TIME%", $"{(_Cooldowns[player.userID] - CurrentTime()).ToString("0")}"); SoundToast(player, msg, 1); return; } string targetId = args.Args[1]; string reason = args.Args[2].Replace("0", ""); BasePlayer target = BasePlayer.Find(targetId) ?? BasePlayer.FindSleeping(targetId); RA_ReportSend(player.UserIDString, target.UserIDString, reason, ""); CuiHelper.DestroyUi(player, ReportLayer); SoundToast(player, lang.GetMessage("Sent", this, player.UserIDString), 2); _Cooldowns[player.userID] = CurrentTime() + _Settings.report_ui_cooldown; break; } } } private void ChatCmdReport(BasePlayer player, string command, string[] args) { var over = Interface.Oxide.CallHook("RustApp_CanOpenReportUI", player); if (over != null) { return; } if (!_Cooldowns.ContainsKey(player.userID)) { _Cooldowns.Add(player.userID, 0); } if (_Cooldowns[player.userID] > CurrentTime()) { var msg = lang.GetMessage("Cooldown", this, player.UserIDString).Replace("%TIME%", $"{(_Cooldowns[player.userID] - CurrentTime()).ToString("0")}"); SoundToast(player, msg, 1); return; } if (args != null && args.Length == 1 && args[0].Length == 17) { var target = BasePlayer.FindAwakeOrSleeping(args[0]); if (target == null || !target.IsConnected) { SoundToast(player, lang.GetMessage("Player.Not.Found", this, player.UserIDString), 1); return; } DrawReportInterface(player, 0, "", false, target); return; } DrawReportInterface(player); } #endregion #region User Manipulation private void SoundInfoToast(BasePlayer player, string text) { SoundToast(player, text, 2); } private void SoundErrorToast(BasePlayer player, string text) { SoundToast(player, text, 1); } private void SoundToast(BasePlayer player, string text, int type) { Effect effect = new Effect("assets/bundled/prefabs/fx/notice/item.select.fx.prefab", player, 0, new Vector3(), new Vector3()); EffectNetwork.Send(effect, player.Connection); player.Command("gametip.showtoast", type, text, 1); } #endregion #region Discord private void RA_ReportSend(string initiator_steam_id, string target_steam_id, string reason, string message = "") { var author = permission.GetUserData(initiator_steam_id); var target = permission.GetUserData(target_steam_id); var list = new DiscordField[4] { new DiscordField(_Settings.discord_translations_nickname, $"```{target.LastSeenNickname}```", false), new DiscordField($"SteamID", $"```{target_steam_id}```", true), new DiscordField(_Settings.discord_translations_reason, @$"```ansi {reason} ```", true), null }; if (message != null && message.Length > 0) { list[3] = new DiscordField(_Settings.discord_translations_comment, $"```{message}```", false); } DiscordEmbed embed = new DiscordEmbed("", $" ", null, list.Where(v => v != null).ToArray(), new DiscordFooter($"{_Settings.discord_translations_report_sent}: {author.LastSeenNickname} [{initiator_steam_id}]", "", "")); DiscordMessage req = new DiscordMessage(null, new DiscordEmbed[1] { embed }); req.Send(_Settings.discord_webhook); } #endregion #region Utils private double CurrentTime() => DateTime.Now.Subtract(new DateTime(1970, 1, 1)).TotalSeconds; private static List Letters = new List { '☼', 's', 't', 'r', 'e', 'т', 'ы', 'в', 'о', 'ч', 'х', 'а', 'р', 'u', 'c', 'h', 'a', 'n', 'z', 'o', '^', 'm', 'l', 'b', 'i', 'p', 'w', 'f', 'k', 'y', 'v', '$', '+', 'x', '1', '®', 'd', '#', 'г', 'ш', 'к', '.', 'я', 'у', 'с', 'ь', 'ц', 'и', 'б', 'е', 'л', 'й', '_', 'м', 'п', 'н', 'g', 'q', '3', '4', '2', ']', 'j', '[', '8', '{', '}', '_', '!', '@', '#', '$', '%', '&', '?', '-', '+', '=', '~', ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'а', 'б', 'в', 'г', 'д', 'е', 'ё', 'ж', 'з', 'и', 'й', 'к', 'л', 'м', 'н', 'о', 'п', 'р', 'с', 'т', 'у', 'ф', 'х', 'ц', 'ч', 'ш', 'щ', 'ь', 'ы', 'ъ', 'э', 'ю', 'я' }; private static string NormalizeString(string text) { string name = ""; foreach (var @char in text) { if (Letters.Contains(@char.ToString().ToLower().ToCharArray()[0])) name += @char; } return name; } private long getUnixTime() { return ((DateTimeOffset)DateTime.UtcNow).ToUnixTimeSeconds(); } #endregion #region Messages public void Log(string ru, string en) { if (lang.GetServerLanguage() == "ru") { Puts(ru); } else { Puts(en); } } public void Warning(string ru, string en) { if (lang.GetServerLanguage() == "ru") { PrintWarning(ru); } else { PrintWarning(en); } } public void Error(string ru, string en) { if (lang.GetServerLanguage() == "ru") { PrintError(ru); } else { PrintError(en); } } #endregion } }