From 9d128f1ff39c208595fdaad5e3245b7d299c2f52 Mon Sep 17 00:00:00 2001 From: Kwoth Date: Thu, 18 Aug 2016 23:00:54 +0200 Subject: [PATCH] Fixes, more stuff, .stats added? --- .../Administration/AdministrationModule.cs | 18 +- .../Modules/ClashOfClans/ClashOfClans.cs | 417 +++++++++------ .../ClashOfClans/ClashOfClansModule.cs | 285 ---------- .../Modules/ClashOfClans/ClashWar.cs | 183 +++++++ src/NadekoBot/Modules/DiscordModule.cs | 3 + .../Games/{GamesModule.cs => Games.cs} | 4 +- .../Modules/Help/{HelpModule.cs => Help.cs} | 8 +- .../Modules/NSFW/{NSFWModule.cs => NSFW.cs} | 7 +- .../Pokemon/{PokemonModule.cs => Pokemon.cs} | 4 +- .../Modules/Searches/Commands/OsuCommands.cs | 4 +- .../{SearchesModule.cs => Searches.cs} | 4 +- .../Modules/Translator/GoogleTranslator.cs | 1 + .../{TranslatorModule.cs => Translator.cs} | 4 +- .../Trello/{TrelloModule.cs => Trello.cs} | 2 +- .../Modules/Utility/Commands/InfoCommands.cs | 2 +- .../Utility/{UtilityModule.cs => Utility.cs} | 13 +- src/NadekoBot/NadekoBot.cs | 59 ++- src/NadekoBot/Services/IStatsService.cs | 15 + src/NadekoBot/Services/Impl/StatsService.cs | 58 ++ src/NadekoBot/project.json | 3 +- src/NadekoBot/project.lock.json | 498 +++++++++++++++++- 21 files changed, 1086 insertions(+), 506 deletions(-) delete mode 100644 src/NadekoBot/Modules/ClashOfClans/ClashOfClansModule.cs create mode 100644 src/NadekoBot/Modules/ClashOfClans/ClashWar.cs rename src/NadekoBot/Modules/Games/{GamesModule.cs => Games.cs} (96%) rename src/NadekoBot/Modules/Help/{HelpModule.cs => Help.cs} (93%) rename src/NadekoBot/Modules/NSFW/{NSFWModule.cs => NSFW.cs} (97%) rename src/NadekoBot/Modules/Pokemon/{PokemonModule.cs => Pokemon.cs} (71%) rename src/NadekoBot/Modules/Searches/{SearchesModule.cs => Searches.cs} (98%) rename src/NadekoBot/Modules/Translator/{TranslatorModule.cs => Translator.cs} (89%) rename src/NadekoBot/Modules/Trello/{TrelloModule.cs => Trello.cs} (99%) rename src/NadekoBot/Modules/Utility/{UtilityModule.cs => Utility.cs} (91%) create mode 100644 src/NadekoBot/Services/IStatsService.cs create mode 100644 src/NadekoBot/Services/Impl/StatsService.cs diff --git a/src/NadekoBot/Modules/Administration/AdministrationModule.cs b/src/NadekoBot/Modules/Administration/AdministrationModule.cs index 2289420d..18e28418 100644 --- a/src/NadekoBot/Modules/Administration/AdministrationModule.cs +++ b/src/NadekoBot/Modules/Administration/AdministrationModule.cs @@ -16,10 +16,11 @@ using System.Text.RegularExpressions; namespace NadekoBot.Modules.Administration { [Module(".", AppendSpace = false)] - public partial class AdministrationModule : DiscordModule + public partial class Administration : DiscordModule { - public AdministrationModule(ILocalization loc, CommandService cmds, IBotConfiguration config, IDiscordClient client) : base(loc, cmds, config, client) + public Administration(ILocalization loc, CommandService cmds, IBotConfiguration config, IDiscordClient client) : base(loc, cmds, config, client) { + } ////todo owner only @@ -188,10 +189,12 @@ namespace NadekoBot.Modules.Administration [LocalizedCommand, LocalizedDescription, LocalizedSummary] [RequireContext(ContextType.Guild)] [RequirePermission(GuildPermission.BanMembers)] - public async Task Ban(IMessage imsg, IGuildUser user, [Remainder] string msg = null) + public async Task Ban(IMessage imsg, IGuildUser user) { var channel = imsg.Channel as ITextChannel; + var msg = ""; + if (!string.IsNullOrWhiteSpace(msg)) { await (await user.CreateDMChannelAsync()).SendMessageAsync($"**You have been BANNED from `{channel.Guild.Name}` server.**\n" + @@ -217,15 +220,10 @@ namespace NadekoBot.Modules.Administration { var channel = imsg.Channel as ITextChannel; - if (user == null) - { - await imsg.Channel.SendMessageAsync("User not found.").ConfigureAwait(false); - return; - } if (!string.IsNullOrWhiteSpace(msg)) { await user.SendMessageAsync($"**You have been SOFT-BANNED from `{channel.Guild.Name}` server.**\n" + - $"Reason: {msg}").ConfigureAwait(false); + $"Reason: {msg}").ConfigureAwait(false); await Task.Delay(2000).ConfigureAwait(false); // temp solution; give time for a message to be send, fu volt } try @@ -492,7 +490,7 @@ namespace NadekoBot.Modules.Administration } } - //todo owner only + ////todo owner only //[LocalizedCommand, LocalizedDescription, LocalizedSummary] //[RequireContext(ContextType.Guild)] //public async Task Die(IMessage imsg) diff --git a/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs b/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs index 18ba920d..23975f05 100644 --- a/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs +++ b/src/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs @@ -1,184 +1,285 @@ -ο»Ώusing Discord; -using Newtonsoft.Json; +ο»Ώusing Discord.Commands; +using NadekoBot.Classes.ClashOfClans; using System; -using System.Linq; +using System.Collections.Concurrent; +using System.Collections.Generic; using System.Text; +using System.Threading.Tasks; +using Discord; +using NadekoBot.Services; +using NadekoBot.Attributes; -namespace NadekoBot.Classes.ClashOfClans +//todo DB +namespace NadekoBot.Modules.ClashOfClans { - public enum DestroyStars + [Module(",",AppendSpace = false)] + internal class ClashOfClans : DiscordModule { - One, Two, Three - } - public enum WarState - { - Started, Ended, Created - } + public static ConcurrentDictionary> ClashWars { get; set; } = new ConcurrentDictionary>(); - internal class Caller - { - public string CallUser { get; set; } - - public DateTime TimeAdded { get; set; } - - public bool BaseDestroyed { get; set; } - - public int Stars { get; set; } = 3; - - public Caller() { } - - public Caller(string callUser, DateTime timeAdded, bool baseDestroyed) + public ClashOfClans(ILocalization loc, CommandService cmds, IBotConfiguration config, IDiscordClient client) : base(loc, cmds, config, client) { - CallUser = callUser; - TimeAdded = timeAdded; - BaseDestroyed = baseDestroyed; } - public void ResetTime() + private static async Task CheckWar(TimeSpan callExpire, ClashWar war) { - TimeAdded = DateTime.UtcNow; - } - - public void Destroy() - { - BaseDestroyed = true; - } - } - - internal class ClashWar - { - private static TimeSpan callExpire => new TimeSpan(2, 0, 0); - - public string EnemyClan { get; set; } - public int Size { get; set; } - - public Caller[] Bases { get; set; } - public WarState WarState { get; set; } = WarState.Created; - //public bool Started { get; set; } = false; - public DateTime StartedAt { get; set; } - //public bool Ended { get; private set; } = false; - - public ulong ServerId { get; set; } - public ulong ChannelId { get; set; } - - [JsonIgnore] - public ITextChannel Channel { get; internal set; } - - /// - /// This init is purely for the deserialization - /// - public ClashWar() { } - - public ClashWar(string enemyClan, int size, ulong serverId, ulong channelId) - { - this.EnemyClan = enemyClan; - this.Size = size; - this.Bases = new Caller[size]; - this.ServerId = serverId; - this.ChannelId = channelId; - this.Channel = NadekoBot.Client.GetGuildsAsync() //nice api you got here volt, - .GetAwaiter() //especially like how getguildsasync isn't async at all internally. - .GetResult() //But hey, lib has to be async kek - .FirstOrDefault(s => s.Id == serverId)? // srsly - .GetChannelsAsync() //wtf is this - .GetAwaiter() // oh i know, its the implementation detail - .GetResult() // and makes library look consistent - .FirstOrDefault(c => c.Id == channelId) // its not common sense to make library work like this. - as ITextChannel; // oh and don't forget to cast it to this arbitrary bullshit - } - - internal void End() - { - //Ended = true; - WarState = WarState.Ended; - } - - internal void Call(string u, int baseNumber) - { - if (baseNumber < 0 || baseNumber >= Bases.Length) - throw new ArgumentException("Invalid base number"); - if (Bases[baseNumber] != null) - throw new ArgumentException("That base is already claimed."); + var Bases = war.Bases; for (var i = 0; i < Bases.Length; i++) { - if (Bases[i]?.BaseDestroyed == false && Bases[i]?.CallUser == u) - throw new ArgumentException($"@{u} You already claimed base #{i + 1}. You can't claim a new one."); - } - - Bases[baseNumber] = new Caller(u.Trim(), DateTime.UtcNow, false); - } - - internal void Start() - { - if (WarState == WarState.Started) - throw new InvalidOperationException("War already started"); - //if (Started) - // throw new InvalidOperationException(); - //Started = true; - WarState = WarState.Started; - StartedAt = DateTime.UtcNow; - foreach (var b in Bases.Where(b => b != null)) - { - b.ResetTime(); - } - } - - internal int Uncall(string user) - { - user = user.Trim(); - for (var i = 0; i < Bases.Length; i++) - { - if (Bases[i]?.CallUser != user) continue; - Bases[i] = null; - return i; - } - throw new InvalidOperationException("You are not participating in that war."); - } - - public string ShortPrint() => - $"`{EnemyClan}` ({Size} v {Size})"; - - public override string ToString() - { - var sb = new StringBuilder(); - - sb.AppendLine($"πŸ”°**WAR AGAINST `{EnemyClan}` ({Size} v {Size}) INFO:**"); - if (WarState == WarState.Created) - sb.AppendLine("`not started`"); - for (var i = 0; i < Bases.Length; i++) - { - if (Bases[i] == null) + if (Bases[i] == null) continue; + if (!Bases[i].BaseDestroyed && DateTime.UtcNow - Bases[i].TimeAdded >= callExpire) { - sb.AppendLine($"`{i + 1}.` ❌*unclaimed*"); + await war.Channel.SendMessageAsync($"β—πŸ”°**Claim from @{Bases[i].CallUser} for a war against {war.ShortPrint()} has expired.**").ConfigureAwait(false); + Bases[i] = null; } - else + } + } + + [LocalizedCommand, LocalizedDescription, LocalizedSummary] + [RequireContext(ContextType.Guild)] + public async Task CreateWar(IMessage imsg, int size, [Remainder] string enemyClan = null) + { + var channel = imsg.Channel as ITextChannel; + + if (!(imsg.Author as IGuildUser).GuildPermissions.ManageChannels) + return; + + if (string.IsNullOrWhiteSpace(enemyClan)) + return; + + if (size < 10 || size > 50 || size % 5 != 0) + { + await imsg.Channel.SendMessageAsync("πŸ’’πŸ”° Not a Valid war size").ConfigureAwait(false); + return; + } + List wars; + if (!ClashWars.TryGetValue(channel.Guild.Id, out wars)) + { + wars = new List(); + if (!ClashWars.TryAdd(channel.Guild.Id, wars)) + return; + } + + + var cw = new ClashWar(enemyClan, size, channel.Guild.Id, imsg.Channel.Id); + //cw.Start(); + + wars.Add(cw); + await imsg.Channel.SendMessageAsync($"β—πŸ”°**CREATED CLAN WAR AGAINST {cw.ShortPrint()}**").ConfigureAwait(false); + } + + [LocalizedCommand, LocalizedDescription, LocalizedSummary] + [RequireContext(ContextType.Guild)] + public async Task StartWar(IMessage imsg, [Remainder] string number = null) + { + var channel = imsg.Channel as ITextChannel; + + int num = 0; + int.TryParse(number, out num); + + var warsInfo = GetWarInfo(imsg, num); + if (warsInfo == null) + { + await imsg.Channel.SendMessageAsync("πŸ’’πŸ”° **That war does not exist.**").ConfigureAwait(false); + return; + } + var war = warsInfo.Item1[warsInfo.Item2]; + try + { + war.Start(); + await imsg.Channel.SendMessageAsync($"πŸ”°**STARTED WAR AGAINST {war.ShortPrint()}**").ConfigureAwait(false); + } + catch + { + await imsg.Channel.SendMessageAsync($"πŸ”°**WAR AGAINST {war.ShortPrint()} HAS ALREADY STARTED**").ConfigureAwait(false); + } + } + + [LocalizedCommand, LocalizedDescription, LocalizedSummary] + [RequireContext(ContextType.Guild)] + public async Task ListWar(IMessage imsg, [Remainder] string number = null) + { + var channel = imsg.Channel as ITextChannel; + + // if number is null, print all wars in a short way + if (string.IsNullOrWhiteSpace(number)) + { + //check if there are any wars + List wars = null; + ClashWars.TryGetValue(channel.Guild.Id, out wars); + if (wars == null || wars.Count == 0) { - if (Bases[i].BaseDestroyed) - { - sb.AppendLine($"`{i + 1}.` βœ… `{Bases[i].CallUser}` {new string('⭐', Bases[i].Stars)}"); - } - else - { - var left = (WarState == WarState.Started) ? callExpire - (DateTime.UtcNow - Bases[i].TimeAdded) : callExpire; - sb.AppendLine($"`{i + 1}.` βœ… `{Bases[i].CallUser}` {left.Hours}h {left.Minutes}m {left.Seconds}s left"); - } + await imsg.Channel.SendMessageAsync("πŸ”° **No active wars.**").ConfigureAwait(false); + return; } + var sb = new StringBuilder(); + sb.AppendLine("πŸ”° **LIST OF ACTIVE WARS**"); + sb.AppendLine("**-------------------------**"); + for (var i = 0; i < wars.Count; i++) + { + sb.AppendLine($"**#{i + 1}.** `Enemy:` **{wars[i].EnemyClan}**"); + sb.AppendLine($"\t\t`Size:` **{wars[i].Size} v {wars[i].Size}**"); + sb.AppendLine("**-------------------------**"); + } + await imsg.Channel.SendMessageAsync(sb.ToString()).ConfigureAwait(false); + return; + } - return sb.ToString(); + var num = 0; + int.TryParse(number, out num); + //if number is not null, print the war needed + var warsInfo = GetWarInfo(imsg, num); + if (warsInfo == null) + { + await imsg.Channel.SendMessageAsync("πŸ’’πŸ”° **That war does not exist.**").ConfigureAwait(false); + return; + } + await imsg.Channel.SendMessageAsync(warsInfo.Item1[warsInfo.Item2].ToString()).ConfigureAwait(false); } - internal int FinishClaim(string user, int stars = 3) + [LocalizedCommand, LocalizedDescription, LocalizedSummary] + [RequireContext(ContextType.Guild)] + public async Task Claim(IMessage imsg, int number, int baseNumber, [Remainder] string other_name = null) { - user = user.Trim(); - for (var i = 0; i < Bases.Length; i++) + var channel = imsg.Channel as ITextChannel; + var warsInfo = GetWarInfo(imsg, number); + if (warsInfo == null || warsInfo.Item1.Count == 0) { - if (Bases[i]?.BaseDestroyed != false || Bases[i]?.CallUser != user) continue; - Bases[i].BaseDestroyed = true; - Bases[i].Stars = stars; - return i; + await imsg.Channel.SendMessageAsync("πŸ’’πŸ”° **That war does not exist.**").ConfigureAwait(false); + return; } - throw new InvalidOperationException($"@{user} You are either not participating in that war, or you already destroyed a base."); + var usr = + string.IsNullOrWhiteSpace(other_name) ? + imsg.Author.Username : + other_name; + try + { + var war = warsInfo.Item1[warsInfo.Item2]; + war.Call(usr, baseNumber - 1); + await imsg.Channel.SendMessageAsync($"πŸ”°**{usr}** claimed a base #{baseNumber} for a war against {war.ShortPrint()}").ConfigureAwait(false); + } + catch (Exception ex) + { + await imsg.Channel.SendMessageAsync($"πŸ’’πŸ”° {ex.Message}").ConfigureAwait(false); + } + } + + [LocalizedCommand, LocalizedDescription, LocalizedSummary] + [RequireContext(ContextType.Guild)] + public async Task ClaimFinish1(IMessage imsg, int number, int baseNumber, [Remainder] string other_name = null) + { + var channel = imsg.Channel as ITextChannel; + await FinishClaim(imsg, number, baseNumber, other_name, 1); + } + + [LocalizedCommand, LocalizedDescription, LocalizedSummary] + [RequireContext(ContextType.Guild)] + public async Task ClaimFinish2(IMessage imsg, int number, int baseNumber, [Remainder] string other_name = null) + { + var channel = imsg.Channel as ITextChannel; + await FinishClaim(imsg, number, baseNumber, other_name, 2); + } + + [LocalizedCommand, LocalizedDescription, LocalizedSummary] + [RequireContext(ContextType.Guild)] + public async Task ClaimFinish(IMessage imsg, int number, int baseNumber, [Remainder] string other_name = null) + { + var channel = imsg.Channel as ITextChannel; + await FinishClaim(imsg, number, baseNumber, other_name); + } + + [LocalizedCommand, LocalizedDescription, LocalizedSummary] + [RequireContext(ContextType.Guild)] + public async Task EndWar(IMessage imsg, int number) + { + var channel = imsg.Channel as ITextChannel; + + var warsInfo = GetWarInfo(imsg,number); + if (warsInfo == null) + { + await imsg.Channel.SendMessageAsync("πŸ’’πŸ”° That war does not exist.").ConfigureAwait(false); + return; + } + warsInfo.Item1[warsInfo.Item2].End(); + await imsg.Channel.SendMessageAsync($"β—πŸ”°**War against {warsInfo.Item1[warsInfo.Item2].ShortPrint()} ended.**").ConfigureAwait(false); + + var size = warsInfo.Item1[warsInfo.Item2].Size; + warsInfo.Item1.RemoveAt(warsInfo.Item2); + } + + [LocalizedCommand, LocalizedDescription, LocalizedSummary] + [RequireContext(ContextType.Guild)] + public async Task Unclaim(IMessage imsg, int number, [Remainder] string otherName = null) + { + var channel = imsg.Channel as ITextChannel; + + var warsInfo = GetWarInfo(imsg, number); + if (warsInfo == null || warsInfo.Item1.Count == 0) + { + await imsg.Channel.SendMessageAsync("πŸ’’πŸ”° **That war does not exist.**").ConfigureAwait(false); + return; + } + var usr = + string.IsNullOrWhiteSpace(otherName) ? + imsg.Author.Username : + otherName; + try + { + var war = warsInfo.Item1[warsInfo.Item2]; + var baseNumber = war.Uncall(usr); + await imsg.Channel.SendMessageAsync($"πŸ”° @{usr} has **UNCLAIMED** a base #{baseNumber + 1} from a war against {war.ShortPrint()}").ConfigureAwait(false); + } + catch (Exception ex) + { + await imsg.Channel.SendMessageAsync($"πŸ’’πŸ”° {ex.Message}").ConfigureAwait(false); + } + } + + private async Task FinishClaim(IMessage imsg, int number, int baseNumber, [Remainder] string other_name, int stars = 3) + { + var channel = imsg.Channel as ITextChannel; + var warInfo = GetWarInfo(imsg, number); + if (warInfo == null || warInfo.Item1.Count == 0) + { + await imsg.Channel.SendMessageAsync("πŸ’’πŸ”° **That war does not exist.**").ConfigureAwait(false); + return; + } + var usr = + string.IsNullOrWhiteSpace(other_name) ? + imsg.Author.Username : + other_name; + + var war = warInfo.Item1[warInfo.Item2]; + try + { + var baseNum = war.FinishClaim(usr, stars); + await imsg.Channel.SendMessageAsync($"β—πŸ”°{imsg.Author.Mention} **DESTROYED** a base #{baseNum + 1} in a war against {war.ShortPrint()}").ConfigureAwait(false); + } + catch (Exception ex) + { + await imsg.Channel.SendMessageAsync($"πŸ’’πŸ”° {ex.Message}").ConfigureAwait(false); + } + } + + private static Tuple, int> GetWarInfo(IMessage imsg, int num) + { + var channel = imsg.Channel as ITextChannel; + //check if there are any wars + List wars = null; + ClashWars.TryGetValue(channel.Guild.Id, out wars); + if (wars == null || wars.Count == 0) + { + return null; + } + // get the number of the war + else if (num < 1 || num > wars.Count) + { + return null; + } + num -= 1; + //get the actual war + return new Tuple, int>(wars, num); } } } diff --git a/src/NadekoBot/Modules/ClashOfClans/ClashOfClansModule.cs b/src/NadekoBot/Modules/ClashOfClans/ClashOfClansModule.cs deleted file mode 100644 index a949577b..00000000 --- a/src/NadekoBot/Modules/ClashOfClans/ClashOfClansModule.cs +++ /dev/null @@ -1,285 +0,0 @@ -ο»Ώusing Discord.Commands; -using NadekoBot.Classes.ClashOfClans; -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Text; -using System.Threading.Tasks; -using Discord; -using NadekoBot.Services; -using NadekoBot.Attributes; - -//todo DB -namespace NadekoBot.Modules.ClashOfClans -{ - [Module(",",AppendSpace = false)] - internal class ClashOfClansModule : DiscordModule - { - public static ConcurrentDictionary> ClashWars { get; set; } = new ConcurrentDictionary>(); - - public ClashOfClansModule(ILocalization loc, CommandService cmds, IBotConfiguration config, IDiscordClient client) : base(loc, cmds, config, client) - { - } - - private static async Task CheckWar(TimeSpan callExpire, ClashWar war) - { - var Bases = war.Bases; - for (var i = 0; i < Bases.Length; i++) - { - if (Bases[i] == null) continue; - if (!Bases[i].BaseDestroyed && DateTime.UtcNow - Bases[i].TimeAdded >= callExpire) - { - await war.Channel.SendMessageAsync($"β—πŸ”°**Claim from @{Bases[i].CallUser} for a war against {war.ShortPrint()} has expired.**").ConfigureAwait(false); - Bases[i] = null; - } - } - } - - [LocalizedCommand, LocalizedDescription, LocalizedSummary] - [RequireContext(ContextType.Guild)] - public async Task CreateWar(IMessage imsg, int size, [Remainder] string enemyClan = null) - { - var channel = imsg.Channel as ITextChannel; - - if (!(imsg.Author as IGuildUser).GuildPermissions.ManageChannels) - return; - - if (string.IsNullOrWhiteSpace(enemyClan)) - return; - - if (size < 10 || size > 50 || size % 5 != 0) - { - await imsg.Channel.SendMessageAsync("πŸ’’πŸ”° Not a Valid war size").ConfigureAwait(false); - return; - } - List wars; - if (!ClashWars.TryGetValue(channel.Guild.Id, out wars)) - { - wars = new List(); - if (!ClashWars.TryAdd(channel.Guild.Id, wars)) - return; - } - - - var cw = new ClashWar(enemyClan, size, channel.Guild.Id, imsg.Channel.Id); - //cw.Start(); - - wars.Add(cw); - await imsg.Channel.SendMessageAsync($"β—πŸ”°**CREATED CLAN WAR AGAINST {cw.ShortPrint()}**").ConfigureAwait(false); - } - - [LocalizedCommand, LocalizedDescription, LocalizedSummary] - [RequireContext(ContextType.Guild)] - public async Task StartWar(IMessage imsg, [Remainder] string number = null) - { - var channel = imsg.Channel as ITextChannel; - - int num = 0; - int.TryParse(number, out num); - - var warsInfo = GetWarInfo(imsg, num); - if (warsInfo == null) - { - await imsg.Channel.SendMessageAsync("πŸ’’πŸ”° **That war does not exist.**").ConfigureAwait(false); - return; - } - var war = warsInfo.Item1[warsInfo.Item2]; - try - { - war.Start(); - await imsg.Channel.SendMessageAsync($"πŸ”°**STARTED WAR AGAINST {war.ShortPrint()}**").ConfigureAwait(false); - } - catch - { - await imsg.Channel.SendMessageAsync($"πŸ”°**WAR AGAINST {war.ShortPrint()} HAS ALREADY STARTED**").ConfigureAwait(false); - } - } - - [LocalizedCommand, LocalizedDescription, LocalizedSummary] - [RequireContext(ContextType.Guild)] - public async Task ListWar(IMessage imsg, [Remainder] string number = null) - { - var channel = imsg.Channel as ITextChannel; - - // if number is null, print all wars in a short way - if (string.IsNullOrWhiteSpace(number)) - { - //check if there are any wars - List wars = null; - ClashWars.TryGetValue(channel.Guild.Id, out wars); - if (wars == null || wars.Count == 0) - { - await imsg.Channel.SendMessageAsync("πŸ”° **No active wars.**").ConfigureAwait(false); - return; - } - - var sb = new StringBuilder(); - sb.AppendLine("πŸ”° **LIST OF ACTIVE WARS**"); - sb.AppendLine("**-------------------------**"); - for (var i = 0; i < wars.Count; i++) - { - sb.AppendLine($"**#{i + 1}.** `Enemy:` **{wars[i].EnemyClan}**"); - sb.AppendLine($"\t\t`Size:` **{wars[i].Size} v {wars[i].Size}**"); - sb.AppendLine("**-------------------------**"); - } - await imsg.Channel.SendMessageAsync(sb.ToString()).ConfigureAwait(false); - return; - - } - var num = 0; - int.TryParse(number, out num); - //if number is not null, print the war needed - var warsInfo = GetWarInfo(imsg, num); - if (warsInfo == null) - { - await imsg.Channel.SendMessageAsync("πŸ’’πŸ”° **That war does not exist.**").ConfigureAwait(false); - return; - } - await imsg.Channel.SendMessageAsync(warsInfo.Item1[warsInfo.Item2].ToString()).ConfigureAwait(false); - } - - [LocalizedCommand, LocalizedDescription, LocalizedSummary] - [RequireContext(ContextType.Guild)] - public async Task Claim(IMessage imsg, int number, int baseNumber, [Remainder] string other_name = null) - { - var channel = imsg.Channel as ITextChannel; - var warsInfo = GetWarInfo(imsg, number); - if (warsInfo == null || warsInfo.Item1.Count == 0) - { - await imsg.Channel.SendMessageAsync("πŸ’’πŸ”° **That war does not exist.**").ConfigureAwait(false); - return; - } - var usr = - string.IsNullOrWhiteSpace(other_name) ? - imsg.Author.Username : - other_name; - try - { - var war = warsInfo.Item1[warsInfo.Item2]; - war.Call(usr, baseNumber - 1); - await imsg.Channel.SendMessageAsync($"πŸ”°**{usr}** claimed a base #{baseNumber} for a war against {war.ShortPrint()}").ConfigureAwait(false); - } - catch (Exception ex) - { - await imsg.Channel.SendMessageAsync($"πŸ’’πŸ”° {ex.Message}").ConfigureAwait(false); - } - } - - [LocalizedCommand, LocalizedDescription, LocalizedSummary] - [RequireContext(ContextType.Guild)] - public async Task ClaimFinish1(IMessage imsg, int number, int baseNumber, [Remainder] string other_name = null) - { - var channel = imsg.Channel as ITextChannel; - await FinishClaim(imsg, number, baseNumber, other_name, 1); - } - - [LocalizedCommand, LocalizedDescription, LocalizedSummary] - [RequireContext(ContextType.Guild)] - public async Task ClaimFinish2(IMessage imsg, int number, int baseNumber, [Remainder] string other_name = null) - { - var channel = imsg.Channel as ITextChannel; - await FinishClaim(imsg, number, baseNumber, other_name, 2); - } - - [LocalizedCommand, LocalizedDescription, LocalizedSummary] - [RequireContext(ContextType.Guild)] - public async Task ClaimFinish(IMessage imsg, int number, int baseNumber, [Remainder] string other_name = null) - { - var channel = imsg.Channel as ITextChannel; - await FinishClaim(imsg, number, baseNumber, other_name); - } - - [LocalizedCommand, LocalizedDescription, LocalizedSummary] - [RequireContext(ContextType.Guild)] - public async Task EndWar(IMessage imsg, int number) - { - var channel = imsg.Channel as ITextChannel; - - var warsInfo = GetWarInfo(imsg,number); - if (warsInfo == null) - { - await imsg.Channel.SendMessageAsync("πŸ’’πŸ”° That war does not exist.").ConfigureAwait(false); - return; - } - warsInfo.Item1[warsInfo.Item2].End(); - await imsg.Channel.SendMessageAsync($"β—πŸ”°**War against {warsInfo.Item1[warsInfo.Item2].ShortPrint()} ended.**").ConfigureAwait(false); - - var size = warsInfo.Item1[warsInfo.Item2].Size; - warsInfo.Item1.RemoveAt(warsInfo.Item2); - } - - [LocalizedCommand, LocalizedDescription, LocalizedSummary] - [RequireContext(ContextType.Guild)] - public async Task Unclaim(IMessage imsg, int number, [Remainder] string otherName = null) - { - var channel = imsg.Channel as ITextChannel; - - var warsInfo = GetWarInfo(imsg, number); - if (warsInfo == null || warsInfo.Item1.Count == 0) - { - await imsg.Channel.SendMessageAsync("πŸ’’πŸ”° **That war does not exist.**").ConfigureAwait(false); - return; - } - var usr = - string.IsNullOrWhiteSpace(otherName) ? - imsg.Author.Username : - otherName; - try - { - var war = warsInfo.Item1[warsInfo.Item2]; - var baseNumber = war.Uncall(usr); - await imsg.Channel.SendMessageAsync($"πŸ”° @{usr} has **UNCLAIMED** a base #{baseNumber + 1} from a war against {war.ShortPrint()}").ConfigureAwait(false); - } - catch (Exception ex) - { - await imsg.Channel.SendMessageAsync($"πŸ’’πŸ”° {ex.Message}").ConfigureAwait(false); - } - } - - private async Task FinishClaim(IMessage imsg, int number, int baseNumber, [Remainder] string other_name, int stars = 3) - { - var channel = imsg.Channel as ITextChannel; - var warInfo = GetWarInfo(imsg, number); - if (warInfo == null || warInfo.Item1.Count == 0) - { - await imsg.Channel.SendMessageAsync("πŸ’’πŸ”° **That war does not exist.**").ConfigureAwait(false); - return; - } - var usr = - string.IsNullOrWhiteSpace(other_name) ? - imsg.Author.Username : - other_name; - - var war = warInfo.Item1[warInfo.Item2]; - try - { - var baseNum = war.FinishClaim(usr, stars); - await imsg.Channel.SendMessageAsync($"β—πŸ”°{imsg.Author.Mention} **DESTROYED** a base #{baseNum + 1} in a war against {war.ShortPrint()}").ConfigureAwait(false); - } - catch (Exception ex) - { - await imsg.Channel.SendMessageAsync($"πŸ’’πŸ”° {ex.Message}").ConfigureAwait(false); - } - } - - private static Tuple, int> GetWarInfo(IMessage imsg, int num) - { - var channel = imsg.Channel as ITextChannel; - //check if there are any wars - List wars = null; - ClashWars.TryGetValue(channel.Guild.Id, out wars); - if (wars == null || wars.Count == 0) - { - return null; - } - // get the number of the war - else if (num < 1 || num > wars.Count) - { - return null; - } - num -= 1; - //get the actual war - return new Tuple, int>(wars, num); - } - } -} diff --git a/src/NadekoBot/Modules/ClashOfClans/ClashWar.cs b/src/NadekoBot/Modules/ClashOfClans/ClashWar.cs new file mode 100644 index 00000000..2b00573e --- /dev/null +++ b/src/NadekoBot/Modules/ClashOfClans/ClashWar.cs @@ -0,0 +1,183 @@ +ο»Ώusing Discord; +using Newtonsoft.Json; +using System; +using System.Linq; +using System.Text; + +namespace NadekoBot.Classes.ClashOfClans +{ + internal class ClashWar + { + public enum DestroyStars + { + One, Two, Three + } + public enum StateOfWar + { + Started, Ended, Created + } + + internal class Caller + { + public string CallUser { get; set; } + + public DateTime TimeAdded { get; set; } + + public bool BaseDestroyed { get; set; } + + public int Stars { get; set; } = 3; + + public Caller() { } + + public Caller(string callUser, DateTime timeAdded, bool baseDestroyed) + { + CallUser = callUser; + TimeAdded = timeAdded; + BaseDestroyed = baseDestroyed; + } + + public void ResetTime() + { + TimeAdded = DateTime.UtcNow; + } + + public void Destroy() + { + BaseDestroyed = true; + } + } + private static TimeSpan callExpire => new TimeSpan(2, 0, 0); + + public string EnemyClan { get; set; } + public int Size { get; set; } + + public Caller[] Bases { get; set; } + public StateOfWar WarState { get; set; } = StateOfWar.Created; + //public bool Started { get; set; } = false; + public DateTime StartedAt { get; set; } + //public bool Ended { get; private set; } = false; + + public ulong ServerId { get; set; } + public ulong ChannelId { get; set; } + + [JsonIgnore] + public ITextChannel Channel { get; internal set; } + + /// + /// This init is purely for the deserialization + /// + public ClashWar() { } + + public ClashWar(string enemyClan, int size, ulong serverId, ulong channelId) + { + this.EnemyClan = enemyClan; + this.Size = size; + this.Bases = new Caller[size]; + this.ServerId = serverId; + this.ChannelId = channelId; + this.Channel = NadekoBot.Client.GetGuildsAsync() //nice api you got here volt, + .GetAwaiter() //especially like how getguildsasync isn't async at all internally. + .GetResult() //But hey, lib has to be async kek + .FirstOrDefault(s => s.Id == serverId)? // srsly + .GetChannelsAsync() //wtf is this + .GetAwaiter() // oh i know, its the implementation detail + .GetResult() // and makes library look consistent + .FirstOrDefault(c => c.Id == channelId) // its not common sense to make library work like this. + as ITextChannel; // oh and don't forget to cast it to this arbitrary bullshit + } + + internal void End() + { + //Ended = true; + WarState = StateOfWar.Ended; + } + + internal void Call(string u, int baseNumber) + { + if (baseNumber < 0 || baseNumber >= Bases.Length) + throw new ArgumentException("Invalid base number"); + if (Bases[baseNumber] != null) + throw new ArgumentException("That base is already claimed."); + for (var i = 0; i < Bases.Length; i++) + { + if (Bases[i]?.BaseDestroyed == false && Bases[i]?.CallUser == u) + throw new ArgumentException($"@{u} You already claimed base #{i + 1}. You can't claim a new one."); + } + + Bases[baseNumber] = new Caller(u.Trim(), DateTime.UtcNow, false); + } + + internal void Start() + { + if (WarState == StateOfWar.Started) + throw new InvalidOperationException("War already started"); + //if (Started) + // throw new InvalidOperationException(); + //Started = true; + WarState = StateOfWar.Started; + StartedAt = DateTime.UtcNow; + foreach (var b in Bases.Where(b => b != null)) + { + b.ResetTime(); + } + } + + internal int Uncall(string user) + { + user = user.Trim(); + for (var i = 0; i < Bases.Length; i++) + { + if (Bases[i]?.CallUser != user) continue; + Bases[i] = null; + return i; + } + throw new InvalidOperationException("You are not participating in that war."); + } + + public string ShortPrint() => + $"`{EnemyClan}` ({Size} v {Size})"; + + public override string ToString() + { + var sb = new StringBuilder(); + + sb.AppendLine($"πŸ”°**WAR AGAINST `{EnemyClan}` ({Size} v {Size}) INFO:**"); + if (WarState == StateOfWar.Created) + sb.AppendLine("`not started`"); + for (var i = 0; i < Bases.Length; i++) + { + if (Bases[i] == null) + { + sb.AppendLine($"`{i + 1}.` ❌*unclaimed*"); + } + else + { + if (Bases[i].BaseDestroyed) + { + sb.AppendLine($"`{i + 1}.` βœ… `{Bases[i].CallUser}` {new string('⭐', Bases[i].Stars)}"); + } + else + { + var left = (WarState == StateOfWar.Started) ? callExpire - (DateTime.UtcNow - Bases[i].TimeAdded) : callExpire; + sb.AppendLine($"`{i + 1}.` βœ… `{Bases[i].CallUser}` {left.Hours}h {left.Minutes}m {left.Seconds}s left"); + } + } + + } + return sb.ToString(); + } + + internal int FinishClaim(string user, int stars = 3) + { + user = user.Trim(); + for (var i = 0; i < Bases.Length; i++) + { + if (Bases[i]?.BaseDestroyed != false || Bases[i]?.CallUser != user) continue; + Bases[i].BaseDestroyed = true; + Bases[i].Stars = stars; + return i; + } + throw new InvalidOperationException($"@{user} You are either not participating in that war, or you already destroyed a base."); + } + } +} diff --git a/src/NadekoBot/Modules/DiscordModule.cs b/src/NadekoBot/Modules/DiscordModule.cs index cb0a5f66..456c83a8 100644 --- a/src/NadekoBot/Modules/DiscordModule.cs +++ b/src/NadekoBot/Modules/DiscordModule.cs @@ -1,6 +1,7 @@ ο»Ώusing Discord; using Discord.Commands; using NadekoBot.Services; +using NLog; namespace NadekoBot.Modules { @@ -10,6 +11,7 @@ namespace NadekoBot.Modules protected CommandService _commands; protected IBotConfiguration _config; protected IDiscordClient _client; + protected Logger _log; public DiscordModule(ILocalization loc, CommandService cmds, IBotConfiguration config,IDiscordClient client) { @@ -17,6 +19,7 @@ namespace NadekoBot.Modules _commands = cmds; _config = config; _client = client; + _log = LogManager.GetCurrentClassLogger(); } } } diff --git a/src/NadekoBot/Modules/Games/GamesModule.cs b/src/NadekoBot/Modules/Games/Games.cs similarity index 96% rename from src/NadekoBot/Modules/Games/GamesModule.cs rename to src/NadekoBot/Modules/Games/Games.cs index f7787c73..49f58e2c 100644 --- a/src/NadekoBot/Modules/Games/GamesModule.cs +++ b/src/NadekoBot/Modules/Games/Games.cs @@ -11,11 +11,11 @@ using NadekoBot.Extensions; namespace NadekoBot.Modules.Games { [Module(">", AppendSpace = false)] - public partial class GamesModule : DiscordModule + public partial class Games : DiscordModule { //todo DB private IEnumerable _8BallResponses; - public GamesModule(ILocalization loc, CommandService cmds, IBotConfiguration config, IDiscordClient client) : base(loc, cmds, config, client) + public Games(ILocalization loc, CommandService cmds, IBotConfiguration config, IDiscordClient client) : base(loc, cmds, config, client) { } diff --git a/src/NadekoBot/Modules/Help/HelpModule.cs b/src/NadekoBot/Modules/Help/Help.cs similarity index 93% rename from src/NadekoBot/Modules/Help/HelpModule.cs rename to src/NadekoBot/Modules/Help/Help.cs index 039cc1c2..0c0a4c78 100644 --- a/src/NadekoBot/Modules/Help/HelpModule.cs +++ b/src/NadekoBot/Modules/Help/Help.cs @@ -12,7 +12,7 @@ using System.Text; namespace NadekoBot.Modules.Help { [Module("-", AppendSpace = false)] - public partial class HelpModule : DiscordModule + public partial class Help : DiscordModule { public string HelpString { get { @@ -20,7 +20,7 @@ namespace NadekoBot.Modules.Help return str + String.Format(str, NadekoBot.Credentials.ClientId); } } - public HelpModule(ILocalization loc, CommandService cmds, IBotConfiguration config, IDiscordClient client) : base(loc, cmds, config, client) + public Help(ILocalization loc, CommandService cmds, IBotConfiguration config, IDiscordClient client) : base(loc, cmds, config, client) { } @@ -66,7 +66,7 @@ namespace NadekoBot.Modules.Help [LocalizedCommand, LocalizedDescription, LocalizedSummary] [RequireContext(ContextType.Guild)] - public async Task Help(IMessage imsg, [Remainder] string comToFind = null) + public async Task H(IMessage imsg, [Remainder] string comToFind = null) { var channel = imsg.Channel as ITextChannel; @@ -106,7 +106,7 @@ namespace NadekoBot.Modules.Help } helpstr = helpstr.Replace((await NadekoBot.Client.GetCurrentUserAsync()).Username , "@BotName"); #if DEBUG - File.WriteAllText("../../../docs/Commands List.md", helpstr.ToString()); + File.WriteAllText("../../../../../docs/Commands List.md", helpstr.ToString()); #else File.WriteAllText("commandlist.md", helpstr.ToString()); #endif diff --git a/src/NadekoBot/Modules/NSFW/NSFWModule.cs b/src/NadekoBot/Modules/NSFW/NSFW.cs similarity index 97% rename from src/NadekoBot/Modules/NSFW/NSFWModule.cs rename to src/NadekoBot/Modules/NSFW/NSFW.cs index 9978da9a..2d897147 100644 --- a/src/NadekoBot/Modules/NSFW/NSFWModule.cs +++ b/src/NadekoBot/Modules/NSFW/NSFW.cs @@ -9,13 +9,14 @@ using NadekoBot.Services; using System.Net.Http; using System.Text.RegularExpressions; using System.Xml.Linq; +using System.Net; namespace NadekoBot.Modules.NSFW { [Module("~", AppendSpace = false)] - public class NSFWModule : DiscordModule + public class NSFW : DiscordModule { - public NSFWModule(ILocalization loc, CommandService cmds, IBotConfiguration config, IDiscordClient client) : base(loc, cmds, config, client) + public NSFW(ILocalization loc, CommandService cmds, IBotConfiguration config, IDiscordClient client) : base(loc, cmds, config, client) { } @@ -212,7 +213,7 @@ namespace NadekoBot.Modules.NSFW http.DefaultRequestHeaders.Clear(); http.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1"); http.DefaultRequestHeaders.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); - var data = await http.GetStringAsync("http://e621.net/post/index.xml?tags=" + Uri.EscapeUriString(tags) + "%20order:random&limit=1"); + var data = await http.GetStreamAsync("http://e621.net/post/index.xml?tags=" + Uri.EscapeUriString(tags) + "%20order:random&limit=1"); var doc = XDocument.Load(data); return doc.Descendants("file_url").FirstOrDefault().Value; } diff --git a/src/NadekoBot/Modules/Pokemon/PokemonModule.cs b/src/NadekoBot/Modules/Pokemon/Pokemon.cs similarity index 71% rename from src/NadekoBot/Modules/Pokemon/PokemonModule.cs rename to src/NadekoBot/Modules/Pokemon/Pokemon.cs index f8a8a6e1..84ce306d 100644 --- a/src/NadekoBot/Modules/Pokemon/PokemonModule.cs +++ b/src/NadekoBot/Modules/Pokemon/Pokemon.cs @@ -7,9 +7,9 @@ using NadekoBot.Services; namespace NadekoBot.Modules.Games.Commands { [Module(">", AppendSpace = false)] - public partial class PokemonModule : DiscordModule + public partial class Pokemon : DiscordModule { - public PokemonModule(ILocalization loc, CommandService cmds, IBotConfiguration config, IDiscordClient client) : base(loc, cmds, config, client) + public Pokemon(ILocalization loc, CommandService cmds, IBotConfiguration config, IDiscordClient client) : base(loc, cmds, config, client) { } diff --git a/src/NadekoBot/Modules/Searches/Commands/OsuCommands.cs b/src/NadekoBot/Modules/Searches/Commands/OsuCommands.cs index 238c9edd..5ec99747 100644 --- a/src/NadekoBot/Modules/Searches/Commands/OsuCommands.cs +++ b/src/NadekoBot/Modules/Searches/Commands/OsuCommands.cs @@ -76,7 +76,7 @@ // var reqString = $"https://osu.ppy.sh/api/get_beatmaps?k={NadekoBot.Creds.OsuAPIKey}&{mapId}"; // var obj = JArray.Parse(await http.GetStringAsync(reqString).ConfigureAwait(false))[0]; // var sb = new System.Text.StringBuilder(); -// var starRating = Math.Round(Double.Parse($"{obj["difficultyrating"]}"), 2); +// var starRating = Math.Round(Double.Parse($"{obj["difficultyrating"]}", CultureInfo.InvariantCulture), 2); // var time = TimeSpan.FromSeconds(Double.Parse($"{obj["total_length"]}")).ToString(@"mm\:ss"); // sb.AppendLine($"{obj["artist"]} - {obj["title"]}, mapped by {obj["creator"]}. https://osu.ppy.sh/s/{obj["beatmapset_id"]}"); // sb.AppendLine($"{starRating} stars, {obj["bpm"]} BPM | AR{obj["diff_approach"]}, CS{obj["diff_size"]}, OD{obj["diff_overall"]} | Length: {time}"); @@ -121,7 +121,7 @@ // { // var mapReqString = $"https://osu.ppy.sh/api/get_beatmaps?k={NadekoBot.Creds.OsuAPIKey}&b={item["beatmap_id"]}"; // var map = JArray.Parse(await http.GetStringAsync(mapReqString).ConfigureAwait(false))[0]; -// var pp = Math.Round(Double.Parse($"{item["pp"]}"), 2); +// var pp = Math.Round(Double.Parse($"{item["pp"]}", CultureInfo.InvariantCulture), 2); // var acc = CalculateAcc(item, m); // var mods = ResolveMods(Int32.Parse($"{item["enabled_mods"]}")); // if (mods != "+") diff --git a/src/NadekoBot/Modules/Searches/SearchesModule.cs b/src/NadekoBot/Modules/Searches/Searches.cs similarity index 98% rename from src/NadekoBot/Modules/Searches/SearchesModule.cs rename to src/NadekoBot/Modules/Searches/Searches.cs index d1383cd3..301f15f9 100644 --- a/src/NadekoBot/Modules/Searches/SearchesModule.cs +++ b/src/NadekoBot/Modules/Searches/Searches.cs @@ -17,13 +17,13 @@ using NadekoBot.Modules.Searches.Commands.Models; namespace NadekoBot.Modules.Searches { [Module("~", AppendSpace = false)] - public class SearchesModule : DiscordModule + public class Searches : DiscordModule { private readonly Random rng; private IYoutubeService _yt { get; } - public SearchesModule(ILocalization loc, CommandService cmds, IBotConfiguration config, IDiscordClient client, IYoutubeService youtube) : base(loc, cmds, config, client) + public Searches(ILocalization loc, CommandService cmds, IBotConfiguration config, IDiscordClient client, IYoutubeService youtube) : base(loc, cmds, config, client) { rng = new Random(); _yt = youtube; diff --git a/src/NadekoBot/Modules/Translator/GoogleTranslator.cs b/src/NadekoBot/Modules/Translator/GoogleTranslator.cs index 8abe5b4a..7421db47 100644 --- a/src/NadekoBot/Modules/Translator/GoogleTranslator.cs +++ b/src/NadekoBot/Modules/Translator/GoogleTranslator.cs @@ -94,6 +94,7 @@ namespace NadekoBot.Modules.Translator { "bn", "bn"}, { "bg", "bg"}, { "ca", "ca"}, + { "zh-TW", "zh-TW"}, { "zh-CN", "zh-CN"}, { "hr", "hr"}, { "cs", "cs"}, diff --git a/src/NadekoBot/Modules/Translator/TranslatorModule.cs b/src/NadekoBot/Modules/Translator/Translator.cs similarity index 89% rename from src/NadekoBot/Modules/Translator/TranslatorModule.cs rename to src/NadekoBot/Modules/Translator/Translator.cs index c060da90..9c6ca537 100644 --- a/src/NadekoBot/Modules/Translator/TranslatorModule.cs +++ b/src/NadekoBot/Modules/Translator/Translator.cs @@ -9,9 +9,9 @@ using NadekoBot.Services; namespace NadekoBot.Modules.Translator { [Module("~", AppendSpace = false)] - public class TranslatorModule : DiscordModule + public class Translator : DiscordModule { - public TranslatorModule(ILocalization loc, CommandService cmds, IBotConfiguration config, IDiscordClient client) : base(loc, cmds, config, client) + public Translator(ILocalization loc, CommandService cmds, IBotConfiguration config, IDiscordClient client) : base(loc, cmds, config, client) { } diff --git a/src/NadekoBot/Modules/Trello/TrelloModule.cs b/src/NadekoBot/Modules/Trello/Trello.cs similarity index 99% rename from src/NadekoBot/Modules/Trello/TrelloModule.cs rename to src/NadekoBot/Modules/Trello/Trello.cs index da52c749..29bc4ea2 100644 --- a/src/NadekoBot/Modules/Trello/TrelloModule.cs +++ b/src/NadekoBot/Modules/Trello/Trello.cs @@ -11,7 +11,7 @@ ////todo rewrite //namespace NadekoBot.Modules.Trello //{ -// internal class TrelloModule : DiscordModule +// internal class Trello : DiscordModule // { // private readonly Timer t = new Timer { Interval = 2000 }; // public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Trello; diff --git a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs index acb8e5de..e068c32b 100644 --- a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; namespace NadekoBot.Modules.Utility { - partial class UtilityModule : DiscordModule + partial class Utility : DiscordModule { [LocalizedCommand, LocalizedDescription, LocalizedSummary] [RequireContext(ContextType.Guild)] diff --git a/src/NadekoBot/Modules/Utility/UtilityModule.cs b/src/NadekoBot/Modules/Utility/Utility.cs similarity index 91% rename from src/NadekoBot/Modules/Utility/UtilityModule.cs rename to src/NadekoBot/Modules/Utility/Utility.cs index 2db615de..b88fe48b 100644 --- a/src/NadekoBot/Modules/Utility/UtilityModule.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -15,9 +15,9 @@ namespace NadekoBot.Modules.Utility { [Module(".", AppendSpace = false)] - public partial class UtilityModule : DiscordModule + public partial class Utility : DiscordModule { - public UtilityModule(ILocalization loc, CommandService cmds, IBotConfiguration config, IDiscordClient client) : base(loc, cmds, config, client) + public Utility(ILocalization loc, CommandService cmds, IBotConfiguration config, IDiscordClient client) : base(loc, cmds, config, client) { } @@ -127,6 +127,15 @@ namespace NadekoBot.Modules.Utility await msg.Reply("`List of roles:` \nβ€’ " + string.Join("\nβ€’ ", (msg.Channel as ITextChannel).Guild.Roles.Except(new[] { guild.EveryoneRole }))); } } + + [LocalizedCommand, LocalizedDescription, LocalizedSummary] + [RequireContext(ContextType.Guild)] + public async Task Stats(IMessage imsg) + { + var channel = imsg.Channel as ITextChannel; + + await channel.SendMessageAsync(await NadekoBot.Stats.Print()); + } } } diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index e9445be9..c40ef836 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -3,6 +3,9 @@ using Discord.Commands; using Discord.WebSocket; using NadekoBot.Services; using NadekoBot.Services.Impl; +using NLog; +using NLog.Config; +using NLog.Targets; using System; using System.Linq; using System.Reflection; @@ -12,6 +15,8 @@ namespace NadekoBot { public class NadekoBot { + private Logger _log; + public static CommandService Commands { get; private set; } public static DiscordSocketClient Client { get; private set; } public static BotConfiguration Config { get; private set; } @@ -19,9 +24,12 @@ namespace NadekoBot public static BotCredentials Credentials { get; private set; } private static YoutubeService Youtube { get; set; } + public static StatsService Stats { get; private set; } public async Task RunAsync(string[] args) { + SetupLogger(); + //create client Client = new DiscordSocketClient(new DiscordSocketConfig { @@ -37,7 +45,9 @@ namespace NadekoBot Config = new BotConfiguration(); Localizer = new Localization(); Youtube = new YoutubeService(); - + Stats = new StatsService(Client); + _log = LogManager.GetCurrentClassLogger(); + //setup DI var depMap = new DependencyMap(); depMap.Add(Localizer); @@ -47,23 +57,56 @@ namespace NadekoBot depMap.Add(Youtube); //connect - await Client.LoginAsync(TokenType.Bot, "MTE5Nzc3MDIxMzE5NTc3NjEw.CpGoCA.yQBJbLWurrjSk7IlGpGzBm-tPTg"); + await Client.LoginAsync(TokenType.Bot, "MTE5Nzc3MDIxMzE5NTc3NjEw.CpdrFA.0rex01uCrn9dBTJOV2tXwMLo0wE"); await Client.ConnectAsync(); - + + _log.Info("Connected"); + //load commands await Commands.LoadAssembly(Assembly.GetEntryAssembly(), depMap); Client.MessageReceived += Client_MessageReceived; - Console.WriteLine(Commands.Commands.Count()); + Console.WriteLine(await Stats.Print()); await Task.Delay(-1); } - private async Task Client_MessageReceived(IMessage arg) + private void SetupLogger() { - var t = await Commands.Execute(arg, 0); - if(!t.IsSuccess && t.Error != CommandError.UnknownCommand) - Console.WriteLine(t.ErrorReason); + try + { + var logConfig = new LoggingConfiguration(); + var consoleTarget = new ColoredConsoleTarget(); + + consoleTarget.Layout = @"${date:format=HH\:mm\:ss} ${logger} | ${message}"; + + logConfig.AddTarget("Console", consoleTarget); + + logConfig.LoggingRules.Add(new LoggingRule("*", LogLevel.Debug, consoleTarget)); + + LogManager.Configuration = logConfig; + } + catch (Exception ex) { + Console.WriteLine(ex); + } + } + + private Task Client_MessageReceived(IMessage imsg) + { + var throwaway = Task.Run(async () => + { + var t = await Commands.Execute(imsg, imsg.Content); + if (t.IsSuccess) + { + _log.Info("Command Executed\n\tFull Message: {0}",imsg.Content); + } + else if (!t.IsSuccess && t.Error != CommandError.UnknownCommand) + { + _log.Warn("Command errored!\n\tFull Message: {0}\n\tError:{1}", imsg.Content, t.Error); + } + }); + + return Task.CompletedTask; } } } diff --git a/src/NadekoBot/Services/IStatsService.cs b/src/NadekoBot/Services/IStatsService.cs new file mode 100644 index 00000000..f43a1cf2 --- /dev/null +++ b/src/NadekoBot/Services/IStatsService.cs @@ -0,0 +1,15 @@ +ο»Ώusing Discord.WebSocket; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Services +{ + public interface IStatsService + { + Task Print(); + Task Reset(); + } +} diff --git a/src/NadekoBot/Services/Impl/StatsService.cs b/src/NadekoBot/Services/Impl/StatsService.cs new file mode 100644 index 00000000..9f50971a --- /dev/null +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -0,0 +1,58 @@ +ο»Ώusing Discord; +using Discord.WebSocket; +using NadekoBot.Extensions; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Services.Impl +{ + public class StatsService : IStatsService + { + private int messageCounter; + private DiscordSocketClient client; + private DateTime started; + + public string BotVersion => "1.0-alpha"; + + public string Heap => Math.Round((double)GC.GetTotalMemory(false) / 1.MiB(), 2).ToString(); + + + public StatsService(DiscordSocketClient client) + { + + this.client = client; + + Reset(); + this.client.MessageReceived += _ => Task.FromResult(messageCounter++); + + this.client.Disconnected += _ => Reset(); + } + public Task Print() => Task.FromResult($@"`Author: Kwoth` `Library: Discord.Net` +`Bot Version: {BotVersion}` +`Bot id: {(client.GetCurrentUser()).Id}` +`Owners' Ids:` +`Uptime: {GetUptimeString()}` +`Servers: {client.GetGuilds().Count} | TextChannels: {client.GetGuilds().SelectMany(g => g.GetChannels().Where(c => c is ITextChannel)).Count()} | VoiceChannels: {client.GetGuilds().SelectMany(g => g.GetChannels().Where(c => c is IVoiceChannel)).Count()}` +`Messages: {messageCounter} ({messageCounter / (double)GetUptime().TotalSeconds:F2}/sec)` `Heap: {Heap} MB`"); + + public Task Reset() + { + messageCounter = 0; + started = DateTime.Now; + return Task.CompletedTask; + } + + public TimeSpan GetUptime() => + DateTime.Now - started; + + public string GetUptimeString() + { + var time = GetUptime(); + return time.Days + " days, " + time.Hours + " hours, and " + time.Minutes + " minutes."; + } + } +} diff --git a/src/NadekoBot/project.json b/src/NadekoBot/project.json index a62bdc9c..a4a1d026 100644 --- a/src/NadekoBot/project.json +++ b/src/NadekoBot/project.json @@ -19,7 +19,8 @@ "Discord.Net.Commands": "1.0.0-dev", "System.Resources.ResourceWriter": "4.0.0-beta-22816", "Google.Apis.YouTube.v3": "1.15.0.582", - "System.Diagnostics.Contracts": "4.0.1" + "System.Diagnostics.Contracts": "4.0.1", + "NLog": "4.4.0-betaV15" }, "frameworks": { diff --git a/src/NadekoBot/project.lock.json b/src/NadekoBot/project.lock.json index 950d70aa..2473e3cd 100644 --- a/src/NadekoBot/project.lock.json +++ b/src/NadekoBot/project.lock.json @@ -339,7 +339,7 @@ "Microsoft.NETCore.Jit/1.0.2": { "type": "package" }, - "Microsoft.NETCore.Platforms/1.0.1": { + "Microsoft.NETCore.Platforms/1.0.2-beta-24410-01": { "type": "package", "compile": { "lib/netstandard1.0/_._": {} @@ -513,6 +513,33 @@ "lib/netstandard1.0/Newtonsoft.Json.dll": {} } }, + "NLog/4.4.0-betav15": { + "type": "package", + "dependencies": { + "Microsoft.Extensions.PlatformAbstractions": "1.0.0", + "NETStandard.Library": "1.6.0", + "System.Collections.NonGeneric": "4.0.1", + "System.ComponentModel.TypeConverter": "4.1.0", + "System.Data.Common": "4.1.0", + "System.Diagnostics.Contracts": "4.0.1", + "System.Diagnostics.StackTrace": "4.0.1", + "System.Diagnostics.TraceSource": "4.0.0", + "System.IO.FileSystem.Watcher": "4.0.0", + "System.Net.NameResolution": "4.0.0", + "System.Net.Requests": "4.0.11", + "System.Reflection.TypeExtensions": "4.1.0", + "System.Runtime.Serialization.Primitives": "4.1.1", + "System.Threading.Thread": "4.0.0", + "System.Threading.ThreadPool": "4.0.10", + "System.Xml.XmlDocument": "4.0.1" + }, + "compile": { + "lib/netstandard1.5/NLog.dll": {} + }, + "runtime": { + "lib/netstandard1.5/NLog.dll": {} + } + }, "Portable.BouncyCastle/1.8.1.1": { "type": "package", "dependencies": { @@ -628,7 +655,7 @@ "lib/netstandard1.1/System.Buffers.dll": {} }, "runtime": { - "lib/netstandard1.1/_._": {} + "lib/netstandard1.1/System.Buffers.dll": {} } }, "System.Collections/4.0.11": { @@ -682,6 +709,41 @@ "lib/netstandard1.0/System.Collections.Immutable.dll": {} } }, + "System.Collections.NonGeneric/4.0.1": { + "type": "package", + "dependencies": { + "System.Diagnostics.Debug": "4.0.11", + "System.Globalization": "4.0.11", + "System.Resources.ResourceManager": "4.0.1", + "System.Runtime": "4.1.0", + "System.Runtime.Extensions": "4.1.0", + "System.Threading": "4.0.11" + }, + "compile": { + "ref/netstandard1.3/System.Collections.NonGeneric.dll": {} + }, + "runtime": { + "lib/netstandard1.3/System.Collections.NonGeneric.dll": {} + } + }, + "System.Collections.Specialized/4.0.1": { + "type": "package", + "dependencies": { + "System.Collections.NonGeneric": "4.0.1", + "System.Globalization": "4.0.11", + "System.Globalization.Extensions": "4.0.1", + "System.Resources.ResourceManager": "4.0.1", + "System.Runtime": "4.1.0", + "System.Runtime.Extensions": "4.1.0", + "System.Threading": "4.0.11" + }, + "compile": { + "ref/netstandard1.3/_._": {} + }, + "runtime": { + "lib/netstandard1.3/System.Collections.Specialized.dll": {} + } + }, "System.ComponentModel/4.0.1": { "type": "package", "dependencies": { @@ -716,6 +778,46 @@ "lib/netstandard1.4/_._": {} } }, + "System.ComponentModel.Primitives/4.1.0": { + "type": "package", + "dependencies": { + "System.ComponentModel": "4.0.1", + "System.Resources.ResourceManager": "4.0.1", + "System.Runtime": "4.1.0" + }, + "compile": { + "ref/netstandard1.0/System.ComponentModel.Primitives.dll": {} + }, + "runtime": { + "lib/netstandard1.0/System.ComponentModel.Primitives.dll": {} + } + }, + "System.ComponentModel.TypeConverter/4.1.0": { + "type": "package", + "dependencies": { + "System.Collections": "4.0.11", + "System.Collections.NonGeneric": "4.0.1", + "System.Collections.Specialized": "4.0.1", + "System.ComponentModel": "4.0.1", + "System.ComponentModel.Primitives": "4.1.0", + "System.Globalization": "4.0.11", + "System.Linq": "4.1.0", + "System.Reflection": "4.1.0", + "System.Reflection.Extensions": "4.0.1", + "System.Reflection.Primitives": "4.0.1", + "System.Reflection.TypeExtensions": "4.1.0", + "System.Resources.ResourceManager": "4.0.1", + "System.Runtime": "4.1.0", + "System.Runtime.Extensions": "4.1.0", + "System.Threading": "4.0.11" + }, + "compile": { + "ref/netstandard1.5/System.ComponentModel.TypeConverter.dll": {} + }, + "runtime": { + "lib/netstandard1.5/System.ComponentModel.TypeConverter.dll": {} + } + }, "System.Console/4.0.0": { "type": "package", "dependencies": { @@ -729,6 +831,25 @@ "ref/netstandard1.3/System.Console.dll": {} } }, + "System.Data.Common/4.1.0": { + "type": "package", + "dependencies": { + "System.Collections": "4.0.11", + "System.Globalization": "4.0.11", + "System.IO": "4.1.0", + "System.Resources.ResourceManager": "4.0.1", + "System.Runtime": "4.1.0", + "System.Runtime.Extensions": "4.1.0", + "System.Text.RegularExpressions": "4.1.0", + "System.Threading.Tasks": "4.0.11" + }, + "compile": { + "ref/netstandard1.2/System.Data.Common.dll": {} + }, + "runtime": { + "lib/netstandard1.2/System.Data.Common.dll": {} + } + }, "System.Diagnostics.Contracts/4.0.1": { "type": "package", "dependencies": { @@ -845,10 +966,10 @@ "System.Runtime.Extensions": "4.1.0" }, "compile": { - "ref/netstandard1.3/_._": {} + "ref/netstandard1.3/System.Diagnostics.StackTrace.dll": {} }, "runtime": { - "lib/netstandard1.3/_._": {} + "lib/netstandard1.3/System.Diagnostics.StackTrace.dll": {} } }, "System.Diagnostics.Tools/4.0.1": { @@ -862,6 +983,33 @@ "ref/netstandard1.0/System.Diagnostics.Tools.dll": {} } }, + "System.Diagnostics.TraceSource/4.0.0": { + "type": "package", + "dependencies": { + "Microsoft.NETCore.Platforms": "1.0.1", + "System.Collections": "4.0.11", + "System.Diagnostics.Debug": "4.0.11", + "System.Globalization": "4.0.11", + "System.Resources.ResourceManager": "4.0.1", + "System.Runtime": "4.1.0", + "System.Runtime.Extensions": "4.1.0", + "System.Threading": "4.0.11", + "runtime.native.System": "4.0.0" + }, + "compile": { + "ref/netstandard1.3/System.Diagnostics.TraceSource.dll": {} + }, + "runtimeTargets": { + "runtimes/unix/lib/netstandard1.3/System.Diagnostics.TraceSource.dll": { + "assetType": "runtime", + "rid": "unix" + }, + "runtimes/win/lib/netstandard1.3/System.Diagnostics.TraceSource.dll": { + "assetType": "runtime", + "rid": "win" + } + } + }, "System.Diagnostics.Tracing/4.1.0": { "type": "package", "dependencies": { @@ -1008,7 +1156,7 @@ "ref/netstandard1.3/System.IO.Compression.ZipFile.dll": {} }, "runtime": { - "lib/netstandard1.3/_._": {} + "lib/netstandard1.3/System.IO.Compression.ZipFile.dll": {} } }, "System.IO.FileSystem/4.0.1": { @@ -1063,9 +1211,17 @@ "ref/netstandard1.3/System.IO.FileSystem.Watcher.dll": {} }, "runtimeTargets": { - "runtimes/osx/lib/netstandard1.3/_._": { + "runtimes/linux/lib/netstandard1.3/System.IO.FileSystem.Watcher.dll": { + "assetType": "runtime", + "rid": "linux" + }, + "runtimes/osx/lib/netstandard1.3/System.IO.FileSystem.Watcher.dll": { "assetType": "runtime", "rid": "osx" + }, + "runtimes/win/lib/netstandard1.3/System.IO.FileSystem.Watcher.dll": { + "assetType": "runtime", + "rid": "win" } } }, @@ -1353,7 +1509,11 @@ "ref/netstandard1.3/System.Net.Security.dll": {} }, "runtimeTargets": { - "runtimes/win/lib/netstandard1.3/_._": { + "runtimes/unix/lib/netstandard1.6/System.Net.Security.dll": { + "assetType": "runtime", + "rid": "unix" + }, + "runtimes/win/lib/netstandard1.3/System.Net.Security.dll": { "assetType": "runtime", "rid": "win" } @@ -1403,16 +1563,20 @@ "lib/netstandard1.3/System.Net.WebSockets.dll": {} } }, - "System.Net.WebSockets.Client/4.0.0": { + "System.Net.WebSockets.Client/4.0.1-beta-24410-01": { "type": "package", "dependencies": { - "Microsoft.NETCore.Platforms": "1.0.1", + "Microsoft.NETCore.Platforms": "1.0.2-beta-24410-01", "Microsoft.Win32.Primitives": "4.0.1", "System.Collections": "4.0.11", "System.Diagnostics.Debug": "4.0.11", "System.Diagnostics.Tracing": "4.1.0", "System.Globalization": "4.0.11", + "System.IO": "4.1.0", + "System.Net.NameResolution": "4.0.0", "System.Net.Primitives": "4.0.11", + "System.Net.Security": "4.0.0", + "System.Net.Sockets": "4.1.0", "System.Net.WebHeaderCollection": "4.0.1", "System.Net.WebSockets": "4.0.0", "System.Resources.ResourceManager": "4.0.1", @@ -1420,10 +1584,14 @@ "System.Runtime.Extensions": "4.1.0", "System.Runtime.Handles": "4.0.1", "System.Runtime.InteropServices": "4.1.0", + "System.Security.Cryptography.Algorithms": "4.2.0", + "System.Security.Cryptography.Primitives": "4.0.0", "System.Security.Cryptography.X509Certificates": "4.1.0", "System.Text.Encoding": "4.0.11", + "System.Text.Encoding.Extensions": "4.0.11", "System.Threading": "4.0.11", - "System.Threading.Tasks": "4.0.11" + "System.Threading.Tasks": "4.0.11", + "System.Threading.Timer": "4.0.1" }, "compile": { "ref/netstandard1.3/System.Net.WebSockets.Client.dll": {} @@ -1584,7 +1752,7 @@ "lib/netstandard1.1/System.Reflection.Metadata.dll": {} }, "runtime": { - "lib/netstandard1.1/_._": {} + "lib/netstandard1.1/System.Reflection.Metadata.dll": {} } }, "System.Reflection.Primitives/4.0.1": { @@ -2131,7 +2299,11 @@ "ref/netstandard1.3/_._": {} }, "runtimeTargets": { - "runtimes/win/lib/netstandard1.3/_._": { + "runtimes/unix/lib/netstandard1.3/System.Threading.Overlapped.dll": { + "assetType": "runtime", + "rid": "unix" + }, + "runtimes/win/lib/netstandard1.3/System.Threading.Overlapped.dll": { "assetType": "runtime", "rid": "win" } @@ -2303,10 +2475,10 @@ "System.Xml.ReaderWriter": "4.0.11" }, "compile": { - "ref/netstandard1.3/_._": {} + "ref/netstandard1.3/System.Xml.XmlDocument.dll": {} }, "runtime": { - "lib/netstandard1.3/_._": {} + "lib/netstandard1.3/System.Xml.XmlDocument.dll": {} } }, "System.Xml.XPath/4.0.1": { @@ -2362,7 +2534,7 @@ "System.Net.Http": "4.1.0", "System.Net.NameResolution": "4.0.0", "System.Net.Sockets": "4.1.0", - "System.Net.WebSockets.Client": "4.0.0", + "System.Net.WebSockets.Client": "4.0.1-beta-24410-01", "System.Reflection.Extensions": "4.0.1", "System.Runtime.InteropServices": "4.1.0", "System.Runtime.InteropServices.RuntimeInformation": "4.0.0", @@ -2746,12 +2918,12 @@ "runtime.json" ] }, - "Microsoft.NETCore.Platforms/1.0.1": { - "sha512": "2G6OjjJzwBfNOO8myRV/nFrbTw5iA+DEm0N+qUqhrOmaVtn4pC77h38I1jsXGw5VH55+dPfQsqHD0We9sCl9FQ==", + "Microsoft.NETCore.Platforms/1.0.2-beta-24410-01": { + "sha512": "uc/pGYdE4sVy3OovFF8hg79MvCxptzICxn0jdA6WusGWZa7VieqFoZYc+a6bHUVhMI0s/7SfBriux0RUq+PpbA==", "type": "package", - "path": "Microsoft.NETCore.Platforms/1.0.1", + "path": "Microsoft.NETCore.Platforms/1.0.2-beta-24410-01", "files": [ - "Microsoft.NETCore.Platforms.1.0.1.nupkg.sha512", + "Microsoft.NETCore.Platforms.1.0.2-beta-24410-01.nupkg.sha512", "Microsoft.NETCore.Platforms.nuspec", "ThirdPartyNotices.txt", "dotnet_library_license.txt", @@ -2938,6 +3110,35 @@ "tools/install.ps1" ] }, + "NLog/4.4.0-betav15": { + "sha512": "LDRcdjv5VG9EWz+mnFqdSolUci+j+DBPIPjm7Xdam3xa1F9Rt7o0UpYoCnNRulqHzpKbU704o7Ad4ck9WxDhnw==", + "type": "package", + "path": "NLog/4.4.0-betav15", + "files": [ + "NLog.4.4.0-betav15.nupkg.sha512", + "NLog.nuspec", + "lib/monoandroid23/NLog.dll", + "lib/monoandroid23/NLog.xml", + "lib/net35/NLog.dll", + "lib/net35/NLog.xml", + "lib/net40/NLog.dll", + "lib/net40/NLog.xml", + "lib/net45/NLog.dll", + "lib/net45/NLog.xml", + "lib/netstandard1.3/NLog.dll", + "lib/netstandard1.3/NLog.xml", + "lib/netstandard1.5/NLog.dll", + "lib/netstandard1.5/NLog.xml", + "lib/sl40/NLog.dll", + "lib/sl40/NLog.xml", + "lib/sl50/NLog.dll", + "lib/sl50/NLog.xml", + "lib/wp80/NLog.dll", + "lib/wp80/NLog.xml", + "lib/xamarinios10/NLog.dll", + "lib/xamarinios10/NLog.xml" + ] + }, "Portable.BouncyCastle/1.8.1.1": { "sha512": "bKqC2Me9ukybNYTBhlYd2sJ6j2kRV7SgB+JfiP2GueYq6QdM4Ym6PYV5eyrqb6KViOyd3zqQfJp0o6UW5ZG+GQ==", "type": "package", @@ -3230,6 +3431,80 @@ "lib/portable-net45+win8+wp8+wpa81/System.Collections.Immutable.xml" ] }, + "System.Collections.NonGeneric/4.0.1": { + "sha512": "hMxFT2RhhlffyCdKLDXjx8WEC5JfCvNozAZxCablAuFRH74SCV4AgzE8yJCh/73bFnEoZgJ9MJmkjQ0dJmnKqA==", + "type": "package", + "path": "System.Collections.NonGeneric/4.0.1", + "files": [ + "System.Collections.NonGeneric.4.0.1.nupkg.sha512", + "System.Collections.NonGeneric.nuspec", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Collections.NonGeneric.dll", + "lib/netstandard1.3/System.Collections.NonGeneric.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Collections.NonGeneric.dll", + "ref/netstandard1.3/System.Collections.NonGeneric.dll", + "ref/netstandard1.3/System.Collections.NonGeneric.xml", + "ref/netstandard1.3/de/System.Collections.NonGeneric.xml", + "ref/netstandard1.3/es/System.Collections.NonGeneric.xml", + "ref/netstandard1.3/fr/System.Collections.NonGeneric.xml", + "ref/netstandard1.3/it/System.Collections.NonGeneric.xml", + "ref/netstandard1.3/ja/System.Collections.NonGeneric.xml", + "ref/netstandard1.3/ko/System.Collections.NonGeneric.xml", + "ref/netstandard1.3/ru/System.Collections.NonGeneric.xml", + "ref/netstandard1.3/zh-hans/System.Collections.NonGeneric.xml", + "ref/netstandard1.3/zh-hant/System.Collections.NonGeneric.xml", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._" + ] + }, + "System.Collections.Specialized/4.0.1": { + "sha512": "/HKQyVP0yH1I0YtK7KJL/28snxHNH/bi+0lgk/+MbURF6ULhAE31MDI+NZDerNWu264YbxklXCCygISgm+HMug==", + "type": "package", + "path": "System.Collections.Specialized/4.0.1", + "files": [ + "System.Collections.Specialized.4.0.1.nupkg.sha512", + "System.Collections.Specialized.nuspec", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Collections.Specialized.dll", + "lib/netstandard1.3/System.Collections.Specialized.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Collections.Specialized.dll", + "ref/netstandard1.3/System.Collections.Specialized.dll", + "ref/netstandard1.3/System.Collections.Specialized.xml", + "ref/netstandard1.3/de/System.Collections.Specialized.xml", + "ref/netstandard1.3/es/System.Collections.Specialized.xml", + "ref/netstandard1.3/fr/System.Collections.Specialized.xml", + "ref/netstandard1.3/it/System.Collections.Specialized.xml", + "ref/netstandard1.3/ja/System.Collections.Specialized.xml", + "ref/netstandard1.3/ko/System.Collections.Specialized.xml", + "ref/netstandard1.3/ru/System.Collections.Specialized.xml", + "ref/netstandard1.3/zh-hans/System.Collections.Specialized.xml", + "ref/netstandard1.3/zh-hant/System.Collections.Specialized.xml", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._" + ] + }, "System.ComponentModel/4.0.1": { "sha512": "oBZFnm7seFiVfugsIyOvQCWobNZs7FzqDV/B7tx20Ep/l3UUFCPDkdTnCNaJZTU27zjeODmy2C/cP60u3D4c9w==", "type": "package", @@ -3364,6 +3639,94 @@ "ref/xamarinwatchos10/_._" ] }, + "System.ComponentModel.Primitives/4.1.0": { + "sha512": "sc/7eVCdxPrp3ljpgTKVaQGUXiW05phNWvtv/m2kocXqrUQvTVWKou1Edas2aDjTThLPZOxPYIGNb/HN0QjURg==", + "type": "package", + "path": "System.ComponentModel.Primitives/4.1.0", + "files": [ + "System.ComponentModel.Primitives.4.1.0.nupkg.sha512", + "System.ComponentModel.Primitives.nuspec", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/System.ComponentModel.Primitives.dll", + "lib/netstandard1.0/System.ComponentModel.Primitives.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/System.ComponentModel.Primitives.dll", + "ref/netstandard1.0/System.ComponentModel.Primitives.dll", + "ref/netstandard1.0/System.ComponentModel.Primitives.xml", + "ref/netstandard1.0/de/System.ComponentModel.Primitives.xml", + "ref/netstandard1.0/es/System.ComponentModel.Primitives.xml", + "ref/netstandard1.0/fr/System.ComponentModel.Primitives.xml", + "ref/netstandard1.0/it/System.ComponentModel.Primitives.xml", + "ref/netstandard1.0/ja/System.ComponentModel.Primitives.xml", + "ref/netstandard1.0/ko/System.ComponentModel.Primitives.xml", + "ref/netstandard1.0/ru/System.ComponentModel.Primitives.xml", + "ref/netstandard1.0/zh-hans/System.ComponentModel.Primitives.xml", + "ref/netstandard1.0/zh-hant/System.ComponentModel.Primitives.xml", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._" + ] + }, + "System.ComponentModel.TypeConverter/4.1.0": { + "sha512": "MnDAlaeJZy9pdB5ZdOlwdxfpI+LJQ6e0hmH7d2+y2LkiD8DRJynyDYl4Xxf3fWFm7SbEwBZh4elcfzONQLOoQw==", + "type": "package", + "path": "System.ComponentModel.TypeConverter/4.1.0", + "files": [ + "System.ComponentModel.TypeConverter.4.1.0.nupkg.sha512", + "System.ComponentModel.TypeConverter.nuspec", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net45/System.ComponentModel.TypeConverter.dll", + "lib/net462/System.ComponentModel.TypeConverter.dll", + "lib/netstandard1.0/System.ComponentModel.TypeConverter.dll", + "lib/netstandard1.5/System.ComponentModel.TypeConverter.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net45/System.ComponentModel.TypeConverter.dll", + "ref/net462/System.ComponentModel.TypeConverter.dll", + "ref/netstandard1.0/System.ComponentModel.TypeConverter.dll", + "ref/netstandard1.0/System.ComponentModel.TypeConverter.xml", + "ref/netstandard1.0/de/System.ComponentModel.TypeConverter.xml", + "ref/netstandard1.0/es/System.ComponentModel.TypeConverter.xml", + "ref/netstandard1.0/fr/System.ComponentModel.TypeConverter.xml", + "ref/netstandard1.0/it/System.ComponentModel.TypeConverter.xml", + "ref/netstandard1.0/ja/System.ComponentModel.TypeConverter.xml", + "ref/netstandard1.0/ko/System.ComponentModel.TypeConverter.xml", + "ref/netstandard1.0/ru/System.ComponentModel.TypeConverter.xml", + "ref/netstandard1.0/zh-hans/System.ComponentModel.TypeConverter.xml", + "ref/netstandard1.0/zh-hant/System.ComponentModel.TypeConverter.xml", + "ref/netstandard1.5/System.ComponentModel.TypeConverter.dll", + "ref/netstandard1.5/System.ComponentModel.TypeConverter.xml", + "ref/netstandard1.5/de/System.ComponentModel.TypeConverter.xml", + "ref/netstandard1.5/es/System.ComponentModel.TypeConverter.xml", + "ref/netstandard1.5/fr/System.ComponentModel.TypeConverter.xml", + "ref/netstandard1.5/it/System.ComponentModel.TypeConverter.xml", + "ref/netstandard1.5/ja/System.ComponentModel.TypeConverter.xml", + "ref/netstandard1.5/ko/System.ComponentModel.TypeConverter.xml", + "ref/netstandard1.5/ru/System.ComponentModel.TypeConverter.xml", + "ref/netstandard1.5/zh-hans/System.ComponentModel.TypeConverter.xml", + "ref/netstandard1.5/zh-hant/System.ComponentModel.TypeConverter.xml", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._" + ] + }, "System.Console/4.0.0": { "sha512": "qSKUSOIiYA/a0g5XXdxFcUFmv1hNICBD7QZ0QhGYVipPIhvpiydY8VZqr1thmCXvmn8aipMg64zuanB4eotK9A==", "type": "package", @@ -3400,6 +3763,55 @@ "ref/xamarinwatchos10/_._" ] }, + "System.Data.Common/4.1.0": { + "sha512": "epU8jeTe7aE7RqGHq9rZ8b0Q4Ah7DgubzHQblgZMSqgW1saW868WmooSyC5ywf8upLBkcVLDu93W9GPWUYsU2Q==", + "type": "package", + "path": "System.Data.Common/4.1.0", + "files": [ + "System.Data.Common.4.1.0.nupkg.sha512", + "System.Data.Common.nuspec", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net451/System.Data.Common.dll", + "lib/netstandard1.2/System.Data.Common.dll", + "lib/portable-net451+win8+wp8+wpa81/System.Data.Common.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net451/System.Data.Common.dll", + "ref/netstandard1.2/System.Data.Common.dll", + "ref/netstandard1.2/System.Data.Common.xml", + "ref/netstandard1.2/de/System.Data.Common.xml", + "ref/netstandard1.2/es/System.Data.Common.xml", + "ref/netstandard1.2/fr/System.Data.Common.xml", + "ref/netstandard1.2/it/System.Data.Common.xml", + "ref/netstandard1.2/ja/System.Data.Common.xml", + "ref/netstandard1.2/ko/System.Data.Common.xml", + "ref/netstandard1.2/ru/System.Data.Common.xml", + "ref/netstandard1.2/zh-hans/System.Data.Common.xml", + "ref/netstandard1.2/zh-hant/System.Data.Common.xml", + "ref/portable-net451+win8+wp8+wpa81/System.Data.Common.dll", + "ref/portable-net451+win8+wp8+wpa81/System.Data.Common.xml", + "ref/portable-net451+win8+wp8+wpa81/de/System.Data.Common.xml", + "ref/portable-net451+win8+wp8+wpa81/es/System.Data.Common.xml", + "ref/portable-net451+win8+wp8+wpa81/fr/System.Data.Common.xml", + "ref/portable-net451+win8+wp8+wpa81/it/System.Data.Common.xml", + "ref/portable-net451+win8+wp8+wpa81/ja/System.Data.Common.xml", + "ref/portable-net451+win8+wp8+wpa81/ko/System.Data.Common.xml", + "ref/portable-net451+win8+wp8+wpa81/ru/System.Data.Common.xml", + "ref/portable-net451+win8+wp8+wpa81/zh-hans/System.Data.Common.xml", + "ref/portable-net451+win8+wp8+wpa81/zh-hant/System.Data.Common.xml", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._" + ] + }, "System.Diagnostics.Contracts/4.0.1": { "sha512": "HvQQjy712vnlpPxaloZYkuE78Gn353L0SJLJVeLcNASeg9c4qla2a1Xq8I7B3jZoDzKPtHTkyVO7AZ5tpeQGuA==", "type": "package", @@ -3731,6 +4143,45 @@ "ref/xamarinwatchos10/_._" ] }, + "System.Diagnostics.TraceSource/4.0.0": { + "sha512": "6WVCczFZKXwpWpzd/iJkYnsmWTSFFiU24Xx/YdHXBcu+nFI/ehTgeqdJQFbtRPzbrO3KtRNjvkhtj4t5/WwWsA==", + "type": "package", + "path": "System.Diagnostics.TraceSource/4.0.0", + "files": [ + "System.Diagnostics.TraceSource.4.0.0.nupkg.sha512", + "System.Diagnostics.TraceSource.nuspec", + "ThirdPartyNotices.txt", + "dotnet_library_license.txt", + "lib/MonoAndroid10/_._", + "lib/MonoTouch10/_._", + "lib/net46/System.Diagnostics.TraceSource.dll", + "lib/xamarinios10/_._", + "lib/xamarinmac20/_._", + "lib/xamarintvos10/_._", + "lib/xamarinwatchos10/_._", + "ref/MonoAndroid10/_._", + "ref/MonoTouch10/_._", + "ref/net46/System.Diagnostics.TraceSource.dll", + "ref/netstandard1.3/System.Diagnostics.TraceSource.dll", + "ref/netstandard1.3/System.Diagnostics.TraceSource.xml", + "ref/netstandard1.3/de/System.Diagnostics.TraceSource.xml", + "ref/netstandard1.3/es/System.Diagnostics.TraceSource.xml", + "ref/netstandard1.3/fr/System.Diagnostics.TraceSource.xml", + "ref/netstandard1.3/it/System.Diagnostics.TraceSource.xml", + "ref/netstandard1.3/ja/System.Diagnostics.TraceSource.xml", + "ref/netstandard1.3/ko/System.Diagnostics.TraceSource.xml", + "ref/netstandard1.3/ru/System.Diagnostics.TraceSource.xml", + "ref/netstandard1.3/zh-hans/System.Diagnostics.TraceSource.xml", + "ref/netstandard1.3/zh-hant/System.Diagnostics.TraceSource.xml", + "ref/xamarinios10/_._", + "ref/xamarinmac20/_._", + "ref/xamarintvos10/_._", + "ref/xamarinwatchos10/_._", + "runtimes/unix/lib/netstandard1.3/System.Diagnostics.TraceSource.dll", + "runtimes/win/lib/net46/System.Diagnostics.TraceSource.dll", + "runtimes/win/lib/netstandard1.3/System.Diagnostics.TraceSource.dll" + ] + }, "System.Diagnostics.Tracing/4.1.0": { "sha512": "vDN1PoMZCkkdNjvZLql592oYJZgS7URcJzJ7bxeBgGtx5UtR5leNm49VmfHGqIffX4FKacHbI3H6UyNSHQknBg==", "type": "package", @@ -5097,12 +5548,12 @@ "ref/xamarinwatchos10/_._" ] }, - "System.Net.WebSockets.Client/4.0.0": { - "sha512": "GY5h9cn0ZVsG4ORQqMytTldrqxet2RC2CSEsgWGf4XNW5jhL5SxzcUZph03xbZsgn7K3qMr+Rq+gkbJNI+FEXg==", + "System.Net.WebSockets.Client/4.0.1-beta-24410-01": { + "sha512": "IOqAcR7k+3LwNI6aL7qN61HcCOA9X4MM9LbrZhDeNbeB/IeWTk7zpeb7kh3d7H678s7ndIqN6a7okO8dAAfcYQ==", "type": "package", - "path": "System.Net.WebSockets.Client/4.0.0", + "path": "System.Net.WebSockets.Client/4.0.1-beta-24410-01", "files": [ - "System.Net.WebSockets.Client.4.0.0.nupkg.sha512", + "System.Net.WebSockets.Client.4.0.1-beta-24410-01.nupkg.sha512", "System.Net.WebSockets.Client.nuspec", "ThirdPartyNotices.txt", "dotnet_library_license.txt", @@ -7421,6 +7872,7 @@ "Microsoft.Extensions.DependencyInjection.Abstractions >= 1.0.0", "Microsoft.Extensions.PlatformAbstractions >= 1.0.0", "Microsoft.NETCore.App >= 1.0.0", + "NLog >= 4.4.0-betaV15", "Newtonsoft.Json >= 9.0.1", "System.Diagnostics.Contracts >= 4.0.1", "System.Resources.ResourceWriter >= 4.0.0-beta-22816"