using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using Newtonsoft.Json; using Oxide.Core; using Oxide.Core.Libraries; using Oxide.Core.Libraries.Covalence; using Oxide.Core.Plugins; namespace Oxide.Plugins { [Info( "DiscordMessages", "Slut", "2.1.8" )] [SuppressMessage( "ReSharper", "UnusedMember.Local" )] internal class DiscordMessages : CovalencePlugin { #region PlayerChat #if RUST private void OnPlayerChat(BasePlayer basePlayer, string message, ConVar.Chat.ChatChannel channel) { if (channel == ConVar.Chat.ChatChannel.Team) { return; } var player = basePlayer.IPlayer; if (player == null) { return; } if (BetterChatMute?.Call("API_IsMuted", player) ?? false) { return; } if (AdminChat?.Call("HasAdminChatEnabled", player) ?? false) { return; } if (!player.HasPermission(AdminPermission)) message = message.Replace("@everyone", "@ everyone").Replace("@here", "@ here"); var chatConfig = GetFeatureConfig(FeatureType.PlayerChat); string discordMessage = GetLang( "PlayerChatFormatNew", null, player.Name, message, DateTime.Now.ToShortTimeString() ); Request.Send(chatConfig.WebhookUrl, new FancyMessage().WithContent(discordMessage).AsTTS(chatConfig.TextToSpeech), this); } #else private void OnUserChat( IPlayer player, string message ) { if ( !GetFeatureConfig( FeatureType.PlayerChat ).Enabled ) { return; } if ( BetterChatMute?.Call( "API_IsMuted", player ) ?? false ) { return; } if ( AdminChat?.Call( "HasAdminChatEnabled", player ) ?? false ) { return; } if ( !player.HasPermission( AdminPermission ) ) { message = message.Replace( "@everyone", "@ everyone" ).Replace( "@here", "@ here" ); } var chatConfig = GetFeatureConfig( FeatureType.PlayerChat ); string discordMessage = GetLang( "PlayerChatFormatNew", null, player.Name, message, DateTime.Now.ToShortTimeString() ); Request.Send( chatConfig.WebhookUrl, new FancyMessage().WithContent( discordMessage ).AsTTS( chatConfig.TextToSpeech ), this ); } #endif #endregion #region Message private void MessageCommand( IPlayer player, string command, string[] args ) { if ( args.Length < 1 ) { SendMessage( player, GetLang( "MessageSyntax", player.Id ) ); return; } var messageConfig = GetFeatureConfig( FeatureType.Message ); int secondsRemaining; if ( OnCooldown( player, CooldownType.MessageCooldown, out secondsRemaining ) ) { SendMessage( player, GetLang( "Cooldown", player.Id, secondsRemaining.ToString() )); return; } string message = string.Join( " ", args.ToArray() ); EmbedBuilder builder = new EmbedBuilder().WithTitle( GetLang( "Embed_MessageTitle" ) ).AddInlineField( GetLang( "Embed_MessagePlayer" ), $"[{player.Name}](https://steamcommunity.com/profiles/{player.Id})" ).AddField( GetLang( "Embed_MessageMessage" ), message ).SetColor( messageConfig.Color ); FancyMessage payload = new FancyMessage().WithContent( messageConfig.Alert ).SetEmbed( builder ); Request.Send( messageConfig.WebhookUrl, payload, response => { if ( response.IsOk ) { SendMessage( player, GetLang( "MessageSent", player.Id ) ); PlayerData data; if ( !_data.Players.TryGetValue( player.Id, out data ) ) { _data.Players.Add( player.Id, data = new PlayerData() ); } data.MessageCooldown = DateTime.UtcNow; if ( messageConfig.LogToConsole ) { Puts( $"MESSAGE ({player.Name}/{player.Id}) : {message}" ); } } else if ( response.IsBad ) { SendMessage( player, GetLang( "MessageNotSent", player.Id ) ); } }, this ); } #endregion #region Classes private class Data { public readonly Dictionary Players = new Dictionary(); } private class PlayerData { public int Reports { get; set; } public DateTime? ReportCooldown { get; set; } public DateTime? MessageCooldown { get; set; } public bool ReportDisabled { get; set; } } public class FancyMessage { [JsonProperty( "content" )] private string Content { get; set; } [JsonProperty( "tts" )] private bool TextToSpeech { get; set; } [JsonProperty( "embeds" )] private EmbedBuilder[] Embeds { get; set; } public FancyMessage WithContent( string value ) { Content = value; return this; } public FancyMessage AsTTS( bool value ) { TextToSpeech = value; return this; } public FancyMessage SetEmbed( EmbedBuilder value ) { Embeds = new[] { value }; return this; } public string GetContent() { return Content; } public bool IsTTS() { return TextToSpeech; } public EmbedBuilder GetEmbed() { return Embeds[0]; } public string ToJson() { return JsonConvert.SerializeObject( this, _instance._jsonSettings ); } } public class EmbedBuilder { public EmbedBuilder() { Fields = new List(); } [JsonProperty( "title" )] private string Title { get; set; } [JsonProperty( "color" )] private int Color { get; set; } [JsonProperty( "fields" )] private List Fields { get; } [JsonProperty( "description" )] private string Description { get; set; } public EmbedBuilder WithTitle( string title ) { Title = title; return this; } public EmbedBuilder WithDescription( string description ) { Description = description; return this; } public EmbedBuilder SetColor( int color ) { Color = color; return this; } public EmbedBuilder SetColor( string color ) { Color = ParseColor( color ); return this; } public EmbedBuilder AddInlineField( string name, object value ) { Fields.Add( new Field( name, value, true ) ); return this; } public EmbedBuilder AddField( string name, object value ) { Fields.Add( new Field( name, value, false ) ); return this; } public EmbedBuilder AddField( Field field ) { Fields.Add( field ); return this; } public EmbedBuilder AddFields( Field[] fields ) { for ( var i = 0; i < fields.Length; i++ ) { Fields.Add( fields[i] ); } return this; } public int GetColor() { return Color; } public string GetTitle() { return Title; } public Field[] GetFields() { return Fields.ToArray(); } private int ParseColor( string input ) { int color; if ( !int.TryParse( input, out color ) ) { color = 3329330; } return color; } public class Field { [JsonProperty( "inline" )] public bool Inline; [JsonProperty( "name" )] public string Name; [JsonProperty( "value" )] public object Value; public Field( string name, object value, bool inline ) { Name = name; Value = value; Inline = inline; } public Field() { } } } private abstract class Response { public int Code { get; set; } public string Message { get; set; } } private class BaseResponse : Response { public bool IsRatelimit => Code == 429; public bool IsOk => ( Code == 200 ) | ( Code == 204 ); public bool IsBad => !IsRatelimit && !IsOk; public RateLimitResponse GetRateLimit() { return Message.Length == 0 ? null : JsonConvert.DeserializeObject( Message ); } } private class Request { private static bool _rateLimited; private static bool _busy; private static Queue _requestQueue; private readonly string _payload; private readonly Plugin _plugin; private readonly Action _response; private readonly string _url; public static void Init() { _requestQueue = new Queue(); } private Request( string url, FancyMessage message, Action response = null, Plugin plugin = null ) { _url = url; _payload = message.ToJson(); _response = response; _plugin = plugin; } private Request( string url, FancyMessage message, Plugin plugin = null ) { _url = url; _payload = message.ToJson(); _plugin = plugin; } private static void SendNextRequest() { if ( _requestQueue.Count == 0 ) { return; } Request request = _requestQueue.Dequeue(); request.Send(); } private static void EnqueueRequest( Request request ) { _requestQueue.Enqueue( request ); } private void Send() { if ( _busy ) { EnqueueRequest( this ); return; } _busy = true; _instance.webrequest.Enqueue( _url, _payload, ( code, rawResponse ) => { var response = new BaseResponse { Message = rawResponse, Code = code }; if ( response.IsRatelimit ) { RateLimitResponse rateLimit = response.GetRateLimit(); if ( rateLimit != null ) { EnqueueRequest( this ); OnRateLimit( rateLimit.RetryAfter ); } } else if ( response.IsBad ) { _instance.PrintWarning( "Failed! Discord responded with code: {0}. Plugin: {1}\n{2}", code, _plugin != null ? _plugin.Name : "Unknown Plugin", response.Message ); } else { try { _response?.Invoke( response ); } catch ( Exception ex ) { Interface.Oxide.LogException( "[DiscordMessages] Request callback raised an exception!", ex ); } } _busy = false; SendNextRequest(); }, _instance, RequestMethod.POST, _instance._headers ); } private static void OnRateLimit( int retryAfter ) { if ( _rateLimited ) { return; } _rateLimited = true; _instance.timer.In( retryAfter / 1000, OnRateLimitEnd ); } private static void OnRateLimitEnd() { _rateLimited = false; SendNextRequest(); } public static void Send( string url, FancyMessage message, Plugin plugin = null ) { new Request( url, message, plugin ).Send(); } public static void Send( string url, FancyMessage message, Action callback, Plugin plugin = null ) { new Request( url, message, callback, plugin ).Send(); } public static void Dispose() { _requestQueue = null; _rateLimited = false; _busy = false; } } private class RateLimitResponse : BaseResponse { [JsonProperty( "retry_after" )] public int RetryAfter { get; set; } } private enum CooldownType { ReportCooldown, MessageCooldown } private enum FeatureType { Ban, Message, Report, PlayerChat, Mute } #endregion #region Configuration private Configuration _config; private class Configuration { public General GeneralSettings { get; set; } = new General(); public Ban BanSettings { get; set; } = new Ban(); public Report ReportSettings { get; set; } = new Report(); public Message MessageSettings { get; set; } = new Message(); public Chat ChatSettings { get; set; } = new Chat(); public Mute MuteSettings { get; set; } = new Mute(); [JsonIgnore] public Dictionary FeatureTypes { get; set; } public static Configuration Defaults() { return new Configuration(); } public class General { public bool Announce { get; set; } = true; } public class Ban : EmbedObject { } public class Message : EmbedObject { public bool LogToConsole { get; set; } = true; public bool SuggestAlias { get; set; } = false; public string Alert { get; set; } = ""; public int Cooldown { get; set; } = 30; } public class Report : EmbedObject { public bool LogToConsole { get; set; } = true; public string Alert { get; set; } = ""; public int Cooldown { get; set; } = 30; } public class Chat : WebhookObject { public bool TextToSpeech { get; set; } = false; } public class Mute : EmbedObject { } public class EmbedObject : WebhookObject { public string Color { get; set; } = "3329330"; } public class WebhookObject { public bool Enabled { get; set; } = true; public string WebhookUrl { get; set; } = "https://support.discordapp.com/hc/en-us/articles/228383668-Intro-to-Webhooks"; } } protected override void LoadConfig() { base.LoadConfig(); _config = Config.ReadObject(); _config.FeatureTypes = new Dictionary { [FeatureType.Ban] = _config.BanSettings, [FeatureType.Report] = _config.ReportSettings, [FeatureType.Message] = _config.MessageSettings, [FeatureType.Mute] = _config.MuteSettings, [FeatureType.PlayerChat] = _config.ChatSettings }; } protected override void SaveConfig() { base.SaveConfig(); Config.WriteObject( _config ); } protected override void LoadDefaultConfig() { PrintWarning( "Generating new config!" ); _config = Configuration.Defaults(); } private T GetFeatureConfig( FeatureType type ) where T : Configuration.WebhookObject { return ( T ) _config.FeatureTypes[type]; } #endregion #region Variables private Data _data; [PluginReference] private readonly Plugin BetterChatMute, AdminChat; private static DiscordMessages _instance; private readonly JsonSerializerSettings _jsonSettings = new JsonSerializerSettings(); private readonly Dictionary _headers = new Dictionary { ["Content-Type"] = "application/json" }; #endregion #region Hooks / Load private void Loaded() { _instance = this; Request.Init(); _jsonSettings.NullValueHandling = NullValueHandling.Ignore; LoadData(); RegisterPermissions(); foreach ( var feature in _config.FeatureTypes ) { Configuration.WebhookObject value = feature.Value; if ( !value.Enabled || value.WebhookUrl != null && value.WebhookUrl != "https://support.discordapp.com/hc/en-us/articles/228383668-Intro-to-Webhooks" ) { continue; } value.Enabled = false; PrintWarning( $"{feature.Key} was enabled however the Webhook is incorrect." ); } RegisterCommands(); CheckHooks(); } private void CheckHooks() { if ( !GetFeatureConfig( FeatureType.PlayerChat ).Enabled ) { #if RUST Unsubscribe(nameof(OnPlayerChat)); #else Unsubscribe( nameof( OnUserChat ) ); #endif } if ( !GetFeatureConfig( FeatureType.Mute ).Enabled ) { Unsubscribe( nameof( OnBetterChatMuted ) ); Unsubscribe( nameof( OnBetterChatTimeMuted ) ); } } private void Unload() { SaveData(); Request.Dispose(); _instance = null; } private void OnServerSave() { SaveData(); } private void RegisterCommands() { if ( GetFeatureConfig( FeatureType.Report ).Enabled ) { AddCovalenceCommand( "report", "ReportCommand", ReportPermission ); AddCovalenceCommand( new[] { "reportadmin", "ra" }, "ReportAdminCommand", AdminPermission ); } if ( GetFeatureConfig( FeatureType.Ban ).Enabled ) { AddCovalenceCommand( "ban", "BanCommand", BanPermission ); } var messageConfig = GetFeatureConfig( FeatureType.Message ); if ( messageConfig.Enabled ) { AddCovalenceCommand( messageConfig.SuggestAlias ? new[] { "message", "suggest" } : new[] { "message" }, "MessageCommand", MessagePermission ); } } protected override void LoadDefaultMessages() { lang.RegisterMessages( new Dictionary { ["ReportSyntax"] = "Syntax error. Please use /report \"name/id\" \"reason\"", ["BanSyntax"] = "Syntax error. Please use /ban \"name/id\" \"reason\"", ["MessageSyntax"] = "Syntax error. Please use /message \"your message\"", ["Multiple"] = "Multiple players found:\n{0}", ["BanMessage"] = "{0} was banned for {1}", ["ReportSent"] = "Your report has been sent!", ["MessageSent"] = "Your message has been sent!", ["NotFound"] = "Unable to find player {0}", ["NoReports"] = "{0} has not been reported yet!", ["ReportDisallowed"] = "You have been blacklisted from reporting players.", ["ReportAccessChanged"] = "Report feature for {0} is now {1}", ["ReportReset"] = "You have reset the report count for {0}", ["Cooldown"] = "You must wait {0} seconds to use this command again.", ["AlreadyBanned"] = "{0} is already banned!", ["NoPermission"] = "You do not have permision for this command!", ["Disabled"] = "This feature is currently disabled.", ["Failed"] = "Your report failed to send, contact the server owner.", ["ToSelf"] = "You cannot perform this action on yourself.", ["ReportTooShort"] = "Your report was too short! Please be more descriptive.", ["PlayerChatFormatNew"] = "[{2}] **{0}:** {1}", ["BanPrefix"] = "Banned: {0}", ["Embed_ReportPlayer"] = "Reporter", ["Embed_ReportTarget"] = "Reported", ["Embed_ReportCount"] = "Times Reported", ["Embed_ReportReason"] = "Reason", ["Embed_Online"] = "Online", ["Embed_Offline"] = "Offline", ["Embed_ReportStatus"] = "Status", ["Embed_ReportTitle"] = "Player Report", ["Embed_MuteTitle"] = "Player Muted", ["Embed_MuteTarget"] = "Player", ["Embed_MutePlayer"] = "Muted by", ["Embed_BanPlayer"] = "Banned by", ["Embed_BanTarget"] = "Player", ["Embed_BanReason"] = "Reason", ["Embed_BanTitle"] = "Player Ban", ["Embed_MessageTitle"] = "Player Message", ["Embed_MessagePlayer"] = "Player", ["Embed_MessageMessage"] = "Message", ["Embed_MuteTime"] = "Time", ["Embed_MuteReason"] = "Reason" }, this ); } #endregion #region Permissions private const string BanPermission = "discordmessages.ban"; private const string ReportPermission = "discordmessages.report"; private const string MessagePermission = "discordmessages.message"; private const string AdminPermission = "discordmessages.admin"; private void RegisterPermissions() { permission.RegisterPermission( BanPermission, this ); permission.RegisterPermission( ReportPermission, this ); permission.RegisterPermission( MessagePermission, this ); permission.RegisterPermission( AdminPermission, this ); } #endregion #region API private void API_SendFancyMessage( string webhookUrl, string content, string embedJsonString, Plugin plugin = null ) { EmbedBuilder embed; try { embed = JsonConvert.DeserializeObject( embedJsonString ); } catch ( JsonSerializationException ) { PrintWarning( "Failed to deserialize json string: {0}", embedJsonString ); return; } FancyMessage payload = new FancyMessage().SetEmbed( embed ).WithContent( content ); Request.Send( webhookUrl, payload, plugin ); } private void API_SendFancyMessage( string webhookUrl, string embedName, int embedColor, string json, string content = null, Plugin plugin = null ) { EmbedBuilder builder = new EmbedBuilder().WithTitle( embedName ).SetColor( embedColor ); EmbedBuilder.Field[] fields; try { fields = JsonConvert.DeserializeObject( json ); } catch ( JsonSerializationException ) { PrintWarning( "Failed to deserialize json string: {0}", json ); return; } builder.AddFields( fields ); FancyMessage payload = new FancyMessage().SetEmbed( builder ).WithContent( content ); Request.Send( webhookUrl, payload, plugin ); } private void API_SendFancyMessage( string webhookUrl, string embedName, string json, string content = null, int embedColor = 3329330, Plugin plugin = null ) { API_SendFancyMessage( webhookUrl, embedName, embedColor, json, content, plugin ); } private void API_SendTextMessage( string webhookUrl, string content, bool tts = false, Plugin plugin = null ) { Request.Send( webhookUrl, new FancyMessage().AsTTS( tts ).WithContent( content ), plugin ); } #endregion #region Report private void ReportAdminCommand( IPlayer player, string command, string[] args ) { IPlayer target = GetPlayer( args[1], player, false ); if ( target == null ) { player.Reply( GetLang( "NotFound", player.Id, args[1] ) ); return; } PlayerData data; switch ( args[0] ) { case "enable": if ( _data.Players.TryGetValue( target.Id, out data ) ) { data.ReportDisabled = false; } player.Reply( GetLang( "ReportAccessChanged", player.Id, target.Name, "enabled" ) ); return; case "disable": if ( !_data.Players.TryGetValue( target.Id, out data ) ) { _data.Players.Add( target.Id, data = new PlayerData() ); } data.ReportDisabled = true; player.Reply( GetLang( "ReportAccessChanged", player.Id, target.Name, "disabled" ) ); return; case "reset": if ( _data.Players.TryGetValue( target.Id, out data ) && data.Reports > 0 ) { data.Reports = 0; player.Reply( GetLang( "ReportReset", player.Id, target.Name ) ); return; } player.Reply( GetLang( "NoReports", player.Id, target.Name ) ); return; } } private void ReportCommand( IPlayer player, string command, string[] args ) { if ( ( player.Name == "Server Console" ) | !player.IsConnected ) { return; } PlayerData data; if ( !_data.Players.TryGetValue( player.Id, out data ) ) { _data.Players.Add( player.Id, data = new PlayerData() ); } else if ( data.ReportDisabled ) { SendMessage( player, GetLang( "ReportDisallowed", player.Id ) ); return; } if ( args.Length < 2 ) { SendMessage( player, GetLang( "ReportSyntax", player.Id ) ); return; } var reportConfig = GetFeatureConfig( FeatureType.Report ); int secondsRemaining; if ( OnCooldown( player, CooldownType.ReportCooldown, out secondsRemaining ) ) { SendMessage( player, GetLang( "Cooldown", player.Id, secondsRemaining.ToString() ) ); return; } IPlayer target = GetPlayer( args[0], player, true ); if ( target == null ) { return; } var reason = args.Skip( 1 ).ToList(); if ( player.Id == target.Id ) { SendMessage( player, GetLang( "ToSelf", player.Id ) ); return; } string[] targetName = target.Name.Split( ' ' ); if ( targetName.Length > 1 ) { for ( var x = 0; x < targetName.Length - 1; x++ ) { if ( reason[x].Equals( targetName[x + 1] ) ) { reason.RemoveAt( x ); } else { break; } } } if ( reason.Count < 1 ) { SendMessage( player, GetLang( "ReportTooShort", player.Id ) ); return; } string cleanReason = string.Join( " ", reason.ToArray() ); PlayerData targetData; if ( !_data.Players.TryGetValue( target.Id, out targetData ) ) { _data.Players.Add( target.Id, targetData = new PlayerData() ); } targetData.Reports++; string status = target.IsConnected ? lang.GetMessage( "Online", null ) : lang.GetMessage( "Offline", null ); EmbedBuilder builder = new EmbedBuilder().WithTitle( GetLang( "Embed_ReportTitle" ) ).SetColor( reportConfig.Color ).AddInlineField( GetLang( "Embed_ReportTarget" ), $"[{target.Name}](https://steamcommunity.com/profiles/{target.Id})" ).AddInlineField( GetLang( "Embed_ReportPlayer" ), $"[{player.Name}](https://steamcommunity.com/profiles/{player.Id})" ).AddInlineField( GetLang( "Embed_ReportStatus" ), status ).AddField( GetLang( "Embed_ReportReason" ), cleanReason ).AddInlineField( GetLang( "Embed_ReportCount" ), targetData.Reports.ToString() ); FancyMessage payload = new FancyMessage().WithContent( reportConfig.Alert ).SetEmbed( builder ); Request.Send( reportConfig.WebhookUrl, payload, response => { if ( response.IsOk ) { SendMessage( player, GetLang( "ReportSent", player.Id ) ); data.ReportCooldown = DateTime.UtcNow; if ( reportConfig.LogToConsole ) { Puts( $"REPORT ({player.Name}/{player.Id}) -> ({target.Name}/{target.Id}): {reason}" ); } } else if ( response.IsBad ) { SendMessage( player, GetLang( "ReportNotSent", player.Id ) ); } }, this ); } #endregion #region Mutes private static string FormatTime( TimeSpan time ) { return $"{( time.Days == 0 ? string.Empty : $"{time.Days} day(s)" )}{( time.Days != 0 && time.Hours != 0 ? ", " : string.Empty )}{( time.Hours == 0 ? string.Empty : $"{time.Hours} hour(s)" )}{( time.Hours != 0 && time.Minutes != 0 ? ", " : string.Empty )}{( time.Minutes == 0 ? string.Empty : $"{time.Minutes} minute(s)" )}{( time.Minutes != 0 && time.Seconds != 0 ? ", " : string.Empty )}{( time.Seconds == 0 ? string.Empty : $"{time.Seconds} second(s)" )}"; } private void OnBetterChatTimeMuted( IPlayer target, IPlayer player, TimeSpan expireDate, string reason ) { SendMute( target, player, expireDate, true, reason ); } private void OnBetterChatMuted( IPlayer target, IPlayer player, string reason ) { SendMute( target, player, TimeSpan.Zero, false, reason ); } private void SendMute( IPlayer target, IPlayer player, TimeSpan expireDate, bool timed, string reason ) { if ( target == null || player == null ) { return; } var muteConfig = GetFeatureConfig( FeatureType.Mute ); EmbedBuilder builder = new EmbedBuilder().WithTitle( GetLang( "Embed_MuteTitle" ) ).AddInlineField( GetLang( "Embed_MuteTarget" ), $"[{target.Name}](https://steamcommunity.com/profiles/{target.Id})" ).AddInlineField( GetLang( "Embed_MutePlayer" ), !player.Id.Equals( "server_console" ) ? $"[{player.Name}](https://steamcommunity.com/profiles/{player.Id})" : player.Name ).AddInlineField( GetLang( "Embed_MuteTime" ), timed ? FormatTime( expireDate ) : "Permanent" ).SetColor( muteConfig.Color ); if ( !string.IsNullOrEmpty( reason ) ) { builder.AddField( GetLang( "Embed_MuteReason" ), reason ); } FancyMessage message = new FancyMessage().SetEmbed( builder ); Request.Send( muteConfig.WebhookUrl, message, this ); } #endregion #region Bans private bool _banFromCommand; private void BanCommand( IPlayer player, string command, string[] args ) { if ( args.Length == 0 ) { SendMessage( player, GetLang( "BanSyntax", player.Id ) ); return; } string reason = args.Length == 1 ? "Banned" : string.Join( " ", args.Skip( 1 ).ToArray() ); IPlayer target = GetPlayer( args[0], player, false ); if ( target != null ) { if ( target.Id == player.Id ) { SendMessage( player, GetLang( "ToSelf", player.Id ) ); return; } ExecuteBan( target, player, reason ); } else { player.Reply( GetLang( "NotFound", player.Id, args[0] ) ); } } private void ExecuteBan( IPlayer target, IPlayer player, string reason ) { if ( target.IsBanned ) { SendMessage( player, GetLang( "AlreadyBanned", player.Id, target.Name ) ); return; } _banFromCommand = true; OnUserBanned( target.Name, target.Id, target.Address, reason, -1, player ); target.Ban( GetLang( "BanPrefix", target.Id ) + reason ); if ( _config.GeneralSettings.Announce ) { server.Broadcast( GetLang( "BanMessage", null, target.Name, reason ) ); } } private void OnUserBanned( string name, string bannedId, string address, string reason, long expiry, IPlayer source = null ) { var banConfig = GetFeatureConfig( FeatureType.Ban ); if ( !banConfig.Enabled ) { return; } EmbedBuilder builder = new EmbedBuilder().WithTitle( GetLang( "Embed_BanTitle" ) ).AddInlineField( GetLang( "Embed_BanTarget" ), $"[{name}](https://steamcommunity.com/profiles/{bannedId})" ); if ( source == null ) { if ( _banFromCommand ) { return; } } else { builder.AddInlineField( GetLang( "Embed_BanPlayer" ), !source.Id.Equals( "server_console" ) ? $"[{source.Name}](https://steamcommunity.com/profiles/{source.Id})" : source.Name ); } builder.AddField( GetLang( "Embed_BanReason" ), reason ); if ( expiry > 0 ) { builder.AddField( "Expiry", DateTimeOffset.FromUnixTimeSeconds( expiry ).LocalDateTime.ToString( CultureInfo.CurrentCulture ) ); } builder.SetColor( banConfig.Color ); FancyMessage message = new FancyMessage().SetEmbed( builder ); Request.Send( banConfig.WebhookUrl, message, this ); _banFromCommand = false; } #endregion #region Helpers private string GetLang( string key, string id = null, params object[] args ) { return args.Length > 0 ? string.Format( lang.GetMessage( key, this, id ), args ) : lang.GetMessage( key, this, id ); } private void SendMessage( IPlayer player, string message ) { player.Reply( message ); } private bool OnCooldown( IPlayer player, CooldownType type, out int secondsRemaining ) { secondsRemaining = 0; PlayerData data; if ( !_data.Players.TryGetValue( player.Id, out data ) ) { return false; } switch ( type ) { case CooldownType.MessageCooldown: { if ( !data.MessageCooldown.HasValue ) { return false; } secondsRemaining = (int)(DateTime.UtcNow - data.MessageCooldown.Value.AddSeconds( GetFeatureConfig( FeatureType.Message ).Cooldown )).TotalSeconds; return secondsRemaining > 0; } case CooldownType.ReportCooldown: { if ( !data.ReportCooldown.HasValue ) { return false; } secondsRemaining = (int)(DateTime.UtcNow - data.ReportCooldown.Value.AddSeconds( GetFeatureConfig( FeatureType.Report ).Cooldown )).TotalSeconds; return secondsRemaining > 0; } default: return false; } } private void SaveData() { Interface.Oxide.DataFileSystem.WriteObject( Name, _data ); } private void LoadData() { _data = Interface.Oxide.DataFileSystem.ReadObject( Name ); } private IPlayer GetPlayer( string nameOrId, IPlayer player, bool sendError ) { if ( nameOrId.IsSteamId() ) { IPlayer result = players.All.ToList().Find( p => p.Id == nameOrId ); return result; } var foundPlayers = new List(); foreach ( IPlayer current in players.Connected ) { if ( string.Equals( current.Name, nameOrId, StringComparison.CurrentCultureIgnoreCase ) ) { return current; } if ( current.Name.ToLower().Contains( nameOrId.ToLower() ) ) { foundPlayers.Add( current ); } } if ( foundPlayers.Count == 0 ) { foreach ( IPlayer all in players.All ) { if ( string.Equals( all.Name, nameOrId, StringComparison.CurrentCultureIgnoreCase ) ) { return all; } if ( all.Name.ToLower().Contains( nameOrId.ToLower() ) ) { foundPlayers.Add( all ); } } } switch ( foundPlayers.Count ) { case 0: if ( !nameOrId.IsSteamId() ) { if ( sendError ) { SendMessage( player, GetLang( "NotFound", player.Id, nameOrId ) ); } } break; case 1: return foundPlayers[0]; default: string[] names = ( from current in foundPlayers select current.Name ).ToArray(); SendMessage( player, GetLang( "Multiple", player.Id, string.Join( ", ", names ) ) ); break; } return null; } #endregion } }