merged dev
This commit is contained in:
		@@ -12,6 +12,9 @@ using Discord.WebSocket;
 | 
			
		||||
using NadekoBot.Services;
 | 
			
		||||
using NadekoBot.Services.Database.Models;
 | 
			
		||||
using Microsoft.EntityFrameworkCore;
 | 
			
		||||
using System.Collections.Immutable;
 | 
			
		||||
using NadekoBot.DataStructures;
 | 
			
		||||
using NLog;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Modules.Administration
 | 
			
		||||
{
 | 
			
		||||
@@ -25,8 +28,11 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
 | 
			
		||||
            private static readonly object _locker = new object();
 | 
			
		||||
 | 
			
		||||
            private new static readonly Logger _log;
 | 
			
		||||
 | 
			
		||||
            static SelfCommands()
 | 
			
		||||
            {
 | 
			
		||||
                _log = LogManager.GetCurrentClassLogger();
 | 
			
		||||
                using (var uow = DbHandler.UnitOfWork())
 | 
			
		||||
                {
 | 
			
		||||
                    var config = uow.BotConfig.GetOrCreate();
 | 
			
		||||
@@ -36,7 +42,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
 | 
			
		||||
                var _ = Task.Run(async () =>
 | 
			
		||||
                {
 | 
			
		||||
                    while(!NadekoBot.Ready)
 | 
			
		||||
                    while (!NadekoBot.Ready)
 | 
			
		||||
                        await Task.Delay(1000);
 | 
			
		||||
 | 
			
		||||
                    foreach (var cmd in NadekoBot.BotConfig.StartupCommands)
 | 
			
		||||
@@ -113,7 +119,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
{Format.Code(GetText("channel"))}: {x.ChannelName}/{x.ChannelId}
 | 
			
		||||
{Format.Code(GetText("command_text"))}: {x.CommandText}";
 | 
			
		||||
                        return str;
 | 
			
		||||
                    })),footer: GetText("page", page + 1))
 | 
			
		||||
                    })), footer: GetText("page", page + 1))
 | 
			
		||||
                         .ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
@@ -123,7 +129,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            public async Task Wait(int miliseconds)
 | 
			
		||||
            {
 | 
			
		||||
                if (miliseconds <= 0)
 | 
			
		||||
                    return;                
 | 
			
		||||
                    return;
 | 
			
		||||
                Context.Message.DeleteAfter(0);
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
@@ -157,7 +163,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if(cmd == null)
 | 
			
		||||
                if (cmd == null)
 | 
			
		||||
                    await ReplyErrorLocalized("scrm_fail").ConfigureAwait(false);
 | 
			
		||||
                else
 | 
			
		||||
                    await ReplyConfirmLocalized("scrm").ConfigureAwait(false);
 | 
			
		||||
@@ -215,9 +221,9 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public static async Task HandleDmForwarding(IUserMessage msg, List<IDMChannel> ownerChannels)
 | 
			
		||||
            public static async Task HandleDmForwarding(IUserMessage msg, ImmutableArray<AsyncLazy<IDMChannel>> ownerChannels)
 | 
			
		||||
            {
 | 
			
		||||
                if (_forwardDMs && ownerChannels.Any())
 | 
			
		||||
                if (_forwardDMs && ownerChannels.Length > 0)
 | 
			
		||||
                {
 | 
			
		||||
                    var title = GetTextStatic("dm_from",
 | 
			
		||||
                                    NadekoBot.Localization.DefaultCultureInfo,
 | 
			
		||||
@@ -238,26 +244,39 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
 | 
			
		||||
                    if (_forwardDMsToAllOwners)
 | 
			
		||||
                    {
 | 
			
		||||
                        await Task.WhenAll(ownerChannels.Where(ch => ch.Recipient.Id != msg.Author.Id)
 | 
			
		||||
                            .Select(ch => ch.SendConfirmAsync(title, toSend))).ConfigureAwait(false);
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        var firstOwnerChannel = ownerChannels.First();
 | 
			
		||||
                        if (firstOwnerChannel.Recipient.Id != msg.Author.Id)
 | 
			
		||||
                        var allOwnerChannels = await Task.WhenAll(ownerChannels
 | 
			
		||||
                            .Select(x => x.Value))
 | 
			
		||||
                            .ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                        foreach (var ownerCh in allOwnerChannels.Where(ch => ch.Recipient.Id != msg.Author.Id))
 | 
			
		||||
                        {
 | 
			
		||||
                            try
 | 
			
		||||
                            {
 | 
			
		||||
                                await firstOwnerChannel.SendConfirmAsync(title, toSend).ConfigureAwait(false);
 | 
			
		||||
                                await ownerCh.SendConfirmAsync(title, toSend).ConfigureAwait(false);
 | 
			
		||||
                            }
 | 
			
		||||
                            catch
 | 
			
		||||
                            {
 | 
			
		||||
                                // ignored
 | 
			
		||||
                                _log.Warn("Can't contact owner with id {0}", ownerCh.Recipient.Id);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                            var firstOwnerChannel = await ownerChannels[0];
 | 
			
		||||
                            if (firstOwnerChannel.Recipient.Id != msg.Author.Id)
 | 
			
		||||
                            {
 | 
			
		||||
                                try
 | 
			
		||||
                                {
 | 
			
		||||
                                    await firstOwnerChannel.SendConfirmAsync(title, toSend).ConfigureAwait(false);
 | 
			
		||||
                                }
 | 
			
		||||
                                catch
 | 
			
		||||
                                {
 | 
			
		||||
                                    // ignored
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
 
 | 
			
		||||
@@ -36,10 +36,7 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
 | 
			
		||||
            static PlantPickCommands()
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
#if !GLOBAL_NADEKO
 | 
			
		||||
                NadekoBot.Client.MessageReceived += PotentialFlowerGeneration;
 | 
			
		||||
#endif
 | 
			
		||||
                generationChannels = new ConcurrentHashSet<ulong>(NadekoBot.AllGuildConfigs
 | 
			
		||||
                    .SelectMany(c => c.GenerateCurrencyChannelIds.Select(obj => obj.ChannelId)));
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -8,59 +8,55 @@ namespace NadekoBot.Modules.Searches.Models
 | 
			
		||||
    {
 | 
			
		||||
        public OverwatchPlayer Player { get; set; }
 | 
			
		||||
 | 
			
		||||
        public class OverwatchResponse
 | 
			
		||||
        {
 | 
			
		||||
            public object _request;
 | 
			
		||||
            public OverwatchPlayer Eu { get; set; }
 | 
			
		||||
            public OverwatchPlayer Kr { get; set; }
 | 
			
		||||
            public OverwatchPlayer Us { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
        public class OverwatchPlayer
 | 
			
		||||
        {
 | 
			
		||||
            public Data data { get; set; }
 | 
			
		||||
            public class Data
 | 
			
		||||
            {
 | 
			
		||||
                public bool Missing { get; set; } = false;
 | 
			
		||||
                public string username { get; set; }
 | 
			
		||||
                public int level { get; set; }
 | 
			
		||||
                public string avatar { get; set; }
 | 
			
		||||
                public string levelFrame { get; set; }
 | 
			
		||||
                public string star { get; set; }
 | 
			
		||||
                [JsonProperty("games")]
 | 
			
		||||
                public OverwatchGames Games { get; set; }
 | 
			
		||||
                [JsonProperty("playtime")]
 | 
			
		||||
                public OverwatchPlaytime Playtime { get; set; }
 | 
			
		||||
                [JsonProperty("competitive")]
 | 
			
		||||
                public OverwatchCompetitive Competitive { get; set; }
 | 
			
		||||
                public class OverwatchGames
 | 
			
		||||
                {
 | 
			
		||||
                    [JsonProperty("quick")]
 | 
			
		||||
                    public OverwatchQG Quick { get; set; }
 | 
			
		||||
                    [JsonProperty("competitive")]
 | 
			
		||||
                    public OverwatchCOMP Competitive { get; set; }
 | 
			
		||||
 | 
			
		||||
                    public class OverwatchQG
 | 
			
		||||
                    {
 | 
			
		||||
                        public string wins { get; set; }
 | 
			
		||||
                    }
 | 
			
		||||
                    public class OverwatchCOMP
 | 
			
		||||
                    {
 | 
			
		||||
                        public string wins { get; set; }
 | 
			
		||||
                        public int lost { get; set; }
 | 
			
		||||
                        public string played { get; set; }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                public class OverwatchCompetitive
 | 
			
		||||
                {
 | 
			
		||||
                    public string rank { get; set; }
 | 
			
		||||
                    public string rank_img { get; set; }
 | 
			
		||||
                }
 | 
			
		||||
                public class OverwatchPlaytime
 | 
			
		||||
                {
 | 
			
		||||
                    public string quick { get; set; }
 | 
			
		||||
                    public string competitive { get; set; }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            public StatsField Stats { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
        //This is to strip the html from patch notes content
 | 
			
		||||
        internal static string StripHTML(string input)
 | 
			
		||||
 | 
			
		||||
        public class StatsField
 | 
			
		||||
        {
 | 
			
		||||
            var re = Regex.Replace(input, "<.*?>", String.Empty);
 | 
			
		||||
            re = Regex.Replace(re, " ", $@" ");
 | 
			
		||||
            return re;
 | 
			
		||||
            public Stats Quickplay { get; set; }
 | 
			
		||||
            public Stats Competitive { get; set; }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public class Stats
 | 
			
		||||
        {
 | 
			
		||||
            [JsonProperty("overall_stats")]
 | 
			
		||||
            public OverallStats OverallStats { get; set; }
 | 
			
		||||
            [JsonProperty("game_stats")]
 | 
			
		||||
            public GameStats GameStats { get; set; }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public class OverallStats
 | 
			
		||||
        {
 | 
			
		||||
            public int? comprank;
 | 
			
		||||
            public int level;
 | 
			
		||||
            public int prestige;
 | 
			
		||||
            public string avatar;
 | 
			
		||||
            public int wins;
 | 
			
		||||
            public int losses;
 | 
			
		||||
            public int games;
 | 
			
		||||
            public string rank_image;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public class GameStats
 | 
			
		||||
        {
 | 
			
		||||
            [JsonProperty("time_played")]
 | 
			
		||||
            public float timePlayed;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        public class Competitive
 | 
			
		||||
        {
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -15,61 +15,67 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
        [Group]
 | 
			
		||||
        public class OverwatchCommands : NadekoSubmodule
 | 
			
		||||
        {
 | 
			
		||||
            public enum Region
 | 
			
		||||
            {
 | 
			
		||||
                Eu,
 | 
			
		||||
                Us,
 | 
			
		||||
                Kr
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            public async Task Overwatch(string region, [Remainder] string query = null)
 | 
			
		||||
            public async Task Overwatch(Region region, [Remainder] string query = null)
 | 
			
		||||
            {
 | 
			
		||||
                if (string.IsNullOrWhiteSpace(query))
 | 
			
		||||
                    return;
 | 
			
		||||
                var battletag = query.Replace("#", "-");
 | 
			
		||||
 | 
			
		||||
                await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
 | 
			
		||||
                try
 | 
			
		||||
                var model = (await GetProfile(region, battletag))?.Stats;
 | 
			
		||||
 | 
			
		||||
                if (model != null)
 | 
			
		||||
                {
 | 
			
		||||
                    await Context.Channel.TriggerTypingAsync().ConfigureAwait(false);
 | 
			
		||||
                    var model = await GetProfile(region, battletag);
 | 
			
		||||
 | 
			
		||||
                    var rankimg = model.Competitive.rank_img;
 | 
			
		||||
                    var rank = model.Competitive.rank;
 | 
			
		||||
 | 
			
		||||
                    if (string.IsNullOrWhiteSpace(rank))
 | 
			
		||||
                    if (model.Competitive == null)
 | 
			
		||||
                    {
 | 
			
		||||
                        var qp = model.Quickplay;
 | 
			
		||||
                        var embed = new EmbedBuilder()
 | 
			
		||||
                            .WithAuthor(eau => eau.WithName($"{model.username}")
 | 
			
		||||
                            .WithAuthor(eau => eau.WithName(query)
 | 
			
		||||
                            .WithUrl($"https://www.overbuff.com/players/pc/{battletag}")
 | 
			
		||||
                            .WithIconUrl($"{model.avatar}"))
 | 
			
		||||
                            .WithThumbnailUrl("https://cdn.discordapp.com/attachments/155726317222887425/255653487512256512/YZ4w2ey.png")
 | 
			
		||||
                            .AddField(fb => fb.WithName(GetText("level")).WithValue($"{model.level}").WithIsInline(true))
 | 
			
		||||
                            .AddField(fb => fb.WithName(GetText("quick_wins")).WithValue($"{model.Games.Quick.wins}").WithIsInline(true))
 | 
			
		||||
                            .WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/255653487512256512/YZ4w2ey.png"))
 | 
			
		||||
                            .WithThumbnailUrl(qp.OverallStats.avatar)
 | 
			
		||||
                            .AddField(fb => fb.WithName(GetText("level")).WithValue((qp.OverallStats.level + (qp.OverallStats.prestige * 100)).ToString()).WithIsInline(true))
 | 
			
		||||
                            .AddField(fb => fb.WithName(GetText("quick_wins")).WithValue(qp.OverallStats.wins.ToString()).WithIsInline(true))
 | 
			
		||||
                            .AddField(fb => fb.WithName(GetText("compet_rank")).WithValue("0").WithIsInline(true))
 | 
			
		||||
                            .AddField(fb => fb.WithName(GetText("quick_playtime")).WithValue($"{model.Playtime.quick}").WithIsInline(true))
 | 
			
		||||
                            .AddField(fb => fb.WithName(GetText("quick_playtime")).WithValue($"{qp.GameStats.timePlayed}hrs").WithIsInline(true))
 | 
			
		||||
                            .WithOkColor();
 | 
			
		||||
                        await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        var qp = model.Quickplay;
 | 
			
		||||
                        var compet = model.Competitive;
 | 
			
		||||
                        var embed = new EmbedBuilder()
 | 
			
		||||
                            .WithAuthor(eau => eau.WithName($"{model.username}")
 | 
			
		||||
                            .WithUrl($"https://www.overbuff.com/players/pc/{battletag}")
 | 
			
		||||
                            .WithIconUrl($"{model.avatar}"))
 | 
			
		||||
                            .WithThumbnailUrl(rankimg)
 | 
			
		||||
                            .AddField(fb => fb.WithName(GetText("level")).WithValue($"{model.level}").WithIsInline(true))
 | 
			
		||||
                            .AddField(fb => fb.WithName(GetText("quick_wins")).WithValue($"{model.Games.Quick.wins}").WithIsInline(true))
 | 
			
		||||
                            .AddField(fb => fb.WithName(GetText("compet_wins")).WithValue($"{model.Games.Competitive.wins}").WithIsInline(true))
 | 
			
		||||
                            .AddField(fb => fb.WithName(GetText("compet_loses")).WithValue($"{model.Games.Competitive.lost}").WithIsInline(true))
 | 
			
		||||
                            .AddField(fb => fb.WithName(GetText("compet_played")).WithValue($"{model.Games.Competitive.played}").WithIsInline(true))
 | 
			
		||||
                            .AddField(fb => fb.WithName(GetText("compet_rank")).WithValue(rank).WithIsInline(true))
 | 
			
		||||
                            .AddField(fb => fb.WithName(GetText("compet_playtime")).WithValue($"{model.Playtime.competitive}").WithIsInline(true))
 | 
			
		||||
                            .AddField(fb => fb.WithName(GetText("quick_playtime")).WithValue($"{model.Playtime.quick}").WithIsInline(true))
 | 
			
		||||
                            .WithAuthor(eau => eau.WithName(query)
 | 
			
		||||
                                .WithUrl($"https://www.overbuff.com/players/pc/{battletag}")
 | 
			
		||||
                                .WithIconUrl(compet.OverallStats.rank_image))
 | 
			
		||||
                            .WithThumbnailUrl(compet.OverallStats.avatar)
 | 
			
		||||
                            .AddField(fb => fb.WithName(GetText("level")).WithValue((qp.OverallStats.level + (qp.OverallStats.prestige * 100)).ToString()).WithIsInline(true))
 | 
			
		||||
                            .AddField(fb => fb.WithName(GetText("quick_wins")).WithValue(qp.OverallStats.wins.ToString()).WithIsInline(true))
 | 
			
		||||
                            .AddField(fb => fb.WithName(GetText("compet_wins")).WithValue(compet.OverallStats.wins.ToString()).WithIsInline(true))
 | 
			
		||||
                            .AddField(fb => fb.WithName(GetText("compet_loses")).WithValue(compet.OverallStats.losses.ToString()).WithIsInline(true))
 | 
			
		||||
                            .AddField(fb => fb.WithName(GetText("compet_played")).WithValue(compet.OverallStats.games.ToString()).WithIsInline(true))
 | 
			
		||||
                            .AddField(fb => fb.WithName(GetText("compet_rank")).WithValue(compet.OverallStats.comprank.ToString()).WithIsInline(true))
 | 
			
		||||
                            .AddField(fb => fb.WithName(GetText("compet_playtime")).WithValue(compet.GameStats.timePlayed + "hrs").WithIsInline(true))
 | 
			
		||||
                            .AddField(fb => fb.WithName(GetText("quick_playtime")).WithValue(qp.GameStats.timePlayed.ToString("F1") + "hrs").WithIsInline(true))
 | 
			
		||||
                            .WithColor(NadekoBot.OkColor);
 | 
			
		||||
                        await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                catch
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    await ReplyErrorLocalized("ow_user_not_found").ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            public async Task<OverwatchApiModel.OverwatchPlayer.Data> GetProfile(string region, string battletag)
 | 
			
		||||
            public async Task<OverwatchApiModel.OverwatchPlayer> GetProfile(Region region, string battletag)
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
@@ -78,11 +84,20 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
                        handler.ServerCertificateCustomValidationCallback = (x, y, z, e) => true;
 | 
			
		||||
                        using (var http = new HttpClient(handler))
 | 
			
		||||
                        {
 | 
			
		||||
                            var url =
 | 
			
		||||
                                await http.GetStringAsync(
 | 
			
		||||
                                    $"https://api.lootbox.eu/pc/{region.ToLower()}/{battletag}/profile");
 | 
			
		||||
                            var model = JsonConvert.DeserializeObject<OverwatchApiModel.OverwatchPlayer>(url);
 | 
			
		||||
                            return model.data;
 | 
			
		||||
                            http.AddFakeHeaders();
 | 
			
		||||
                            var url = $"https://owapi.nadekobot.me/api/v3/u/{battletag}/stats";
 | 
			
		||||
                            System.Console.WriteLine(url);
 | 
			
		||||
                            var res = await http.GetStringAsync($"https://owapi.nadekobot.me/api/v3/u/{battletag}/stats");
 | 
			
		||||
                            var model = JsonConvert.DeserializeObject<OverwatchApiModel.OverwatchResponse>(res);
 | 
			
		||||
                            switch (region)
 | 
			
		||||
                            {
 | 
			
		||||
                                case Region.Eu:
 | 
			
		||||
                                    return model.Eu;
 | 
			
		||||
                                case Region.Kr:
 | 
			
		||||
                                    return model.Kr;
 | 
			
		||||
                                default:
 | 
			
		||||
                                    return model.Us;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,8 @@ using NadekoBot.Modules.Games;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using NadekoBot.DataStructures;
 | 
			
		||||
using System.Diagnostics;
 | 
			
		||||
using System.Collections.Immutable;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Services
 | 
			
		||||
{
 | 
			
		||||
@@ -34,7 +36,7 @@ namespace NadekoBot.Services
 | 
			
		||||
        private readonly CommandService _commandService;
 | 
			
		||||
        private readonly Logger _log;
 | 
			
		||||
 | 
			
		||||
        private List<IDMChannel> OwnerChannels { get; set; } = new List<IDMChannel>();
 | 
			
		||||
        private ImmutableArray<AsyncLazy<IDMChannel>> ownerChannels { get; set; } = new ImmutableArray<AsyncLazy<IDMChannel>>();
 | 
			
		||||
 | 
			
		||||
        public event Func<IUserMessage, CommandInfo, Task> CommandExecuted = delegate { return Task.CompletedTask; };
 | 
			
		||||
 | 
			
		||||
@@ -84,28 +86,15 @@ namespace NadekoBot.Services
 | 
			
		||||
            var _ = Task.Run(async () =>
 | 
			
		||||
            {
 | 
			
		||||
                await Task.Delay(5000).ConfigureAwait(false);
 | 
			
		||||
                OwnerChannels = (await Task.WhenAll(_client.Guilds.SelectMany(g => g.Users)
 | 
			
		||||
                        .Where(u => NadekoBot.Credentials.OwnerIds.Contains(u.Id))
 | 
			
		||||
                        .Distinct(new GuildUserComparer())
 | 
			
		||||
                        .Select(async u =>
 | 
			
		||||
                        {
 | 
			
		||||
                            try
 | 
			
		||||
                            {
 | 
			
		||||
                                return await u.CreateDMChannelAsync();
 | 
			
		||||
                            }
 | 
			
		||||
                            catch
 | 
			
		||||
                            {
 | 
			
		||||
                                return null;
 | 
			
		||||
                            }
 | 
			
		||||
                        })))
 | 
			
		||||
                    .Where(ch => ch != null)
 | 
			
		||||
                    .OrderBy(x => NadekoBot.Credentials.OwnerIds.IndexOf(x.Id))
 | 
			
		||||
                    .ToList();
 | 
			
		||||
 | 
			
		||||
                if (!OwnerChannels.Any())
 | 
			
		||||
                _client.GetGuilds().SelectMany(g => g.Users);
 | 
			
		||||
 | 
			
		||||
                LoadOwnerChannels();
 | 
			
		||||
 | 
			
		||||
                if (!ownerChannels.Any())
 | 
			
		||||
                    _log.Warn("No owner channels created! Make sure you've specified correct OwnerId in the credentials.json file.");
 | 
			
		||||
                else
 | 
			
		||||
                    _log.Info($"Created {OwnerChannels.Count} out of {NadekoBot.Credentials.OwnerIds.Length} owner message channels.");
 | 
			
		||||
                    _log.Info($"Created {ownerChannels.Length} out of {NadekoBot.Credentials.OwnerIds.Length} owner message channels.");
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            _client.MessageReceived += MessageReceivedHandler;
 | 
			
		||||
@@ -133,6 +122,36 @@ namespace NadekoBot.Services
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private void LoadOwnerChannels()
 | 
			
		||||
        {
 | 
			
		||||
            var hs = new HashSet<ulong>(NadekoBot.Credentials.OwnerIds);
 | 
			
		||||
            var channels = new Dictionary<ulong, AsyncLazy<IDMChannel>>();
 | 
			
		||||
 | 
			
		||||
            foreach (var s in _client.Shards)
 | 
			
		||||
            {
 | 
			
		||||
                if(hs.Count == 0)
 | 
			
		||||
                    break;
 | 
			
		||||
                    foreach (var g in s.Guilds)
 | 
			
		||||
                    {
 | 
			
		||||
                        if(hs.Count == 0)
 | 
			
		||||
                            break;
 | 
			
		||||
 | 
			
		||||
                        foreach (var u in g.Users)
 | 
			
		||||
                        {
 | 
			
		||||
                            if(hs.Remove(u.Id))
 | 
			
		||||
                            {
 | 
			
		||||
                                channels.Add(u.Id, new AsyncLazy<IDMChannel>(async () => await u.CreateDMChannelAsync()));
 | 
			
		||||
                                if(hs.Count == 0)   
 | 
			
		||||
                                        break;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            ownerChannels = channels.OrderBy(x => NadekoBot.Credentials.OwnerIds.IndexOf(x.Key))
 | 
			
		||||
                    .Select(x => x.Value)
 | 
			
		||||
                    .ToImmutableArray();
 | 
			
		||||
        }
 | 
			
		||||
        private async Task<bool> TryRunCleverbot(IUserMessage usrMsg, SocketGuild guild)
 | 
			
		||||
        {
 | 
			
		||||
            if (guild == null)
 | 
			
		||||
@@ -427,7 +446,7 @@ namespace NadekoBot.Services
 | 
			
		||||
 | 
			
		||||
                    await usrMsg.Channel.SendMessageAsync(Help.DMHelpString).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                    await SelfCommands.HandleDmForwarding(usrMsg, OwnerChannels).ConfigureAwait(false);
 | 
			
		||||
                    await SelfCommands.HandleDmForwarding(usrMsg, ownerChannels).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user