Huge amounts of changes, hopefully nothing broken
This commit is contained in:
		@@ -85,11 +85,11 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                {
 | 
			
		||||
                    var msg = imsg as IUserMessage;
 | 
			
		||||
                    if (msg == null || msg.Author.IsBot)
 | 
			
		||||
                        return Task.CompletedTask;
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    var channel = msg.Channel as ITextChannel;
 | 
			
		||||
                    if (channel == null)
 | 
			
		||||
                        return Task.CompletedTask;
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    var t = Task.Run(async () =>
 | 
			
		||||
                    {
 | 
			
		||||
@@ -113,20 +113,18 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                        }
 | 
			
		||||
                        catch { }
 | 
			
		||||
                    });
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                    return;
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                NadekoBot.Client.UserJoined += (usr) =>
 | 
			
		||||
                NadekoBot.Client.UserJoined += async (usr) =>
 | 
			
		||||
                {
 | 
			
		||||
                    if (usr.IsBot)
 | 
			
		||||
                        return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                    AntiRaidSetting settings;
 | 
			
		||||
                    if (!antiRaidGuilds.TryGetValue(usr.Guild.Id, out settings))
 | 
			
		||||
                        return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                    var t = Task.Run(async () =>
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        if (usr.IsBot)
 | 
			
		||||
                            return;
 | 
			
		||||
                        AntiRaidSetting settings;
 | 
			
		||||
                        if (!antiRaidGuilds.TryGetValue(usr.Guild.Id, out settings))
 | 
			
		||||
                            return;
 | 
			
		||||
                        if (!settings.RaidUsers.Add(usr))
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
@@ -143,9 +141,9 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
 | 
			
		||||
                        settings.RaidUsers.TryRemove(usr);
 | 
			
		||||
                        --settings.UsersCount;
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                    }
 | 
			
		||||
                    catch { }
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -26,26 +26,22 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                AutoAssignedRoles = new ConcurrentDictionary<ulong, ulong>(NadekoBot.AllGuildConfigs.Where(x => x.AutoAssignRoleId != 0)
 | 
			
		||||
                    .ToDictionary(k => k.GuildId, v => v.AutoAssignRoleId));
 | 
			
		||||
                _log = LogManager.GetCurrentClassLogger();
 | 
			
		||||
                NadekoBot.Client.UserJoined += (user) =>
 | 
			
		||||
                NadekoBot.Client.UserJoined += async (user) =>
 | 
			
		||||
                {
 | 
			
		||||
                    var t = Task.Run(async () =>
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            ulong roleId = 0;
 | 
			
		||||
                            AutoAssignedRoles.TryGetValue(user.Guild.Id, out roleId);
 | 
			
		||||
                        ulong roleId = 0;
 | 
			
		||||
                        AutoAssignedRoles.TryGetValue(user.Guild.Id, out roleId);
 | 
			
		||||
 | 
			
		||||
                            if (roleId == 0)
 | 
			
		||||
                                return;
 | 
			
		||||
                        if (roleId == 0)
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                            var role = user.Guild.Roles.FirstOrDefault(r => r.Id == roleId);
 | 
			
		||||
                        var role = user.Guild.Roles.FirstOrDefault(r => r.Id == roleId);
 | 
			
		||||
 | 
			
		||||
                            if (role != null)
 | 
			
		||||
                                await user.AddRolesAsync(role).ConfigureAwait(false);
 | 
			
		||||
                        }
 | 
			
		||||
                        catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
                    });
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                        if (role != null)
 | 
			
		||||
                            await user.AddRolesAsync(role).ConfigureAwait(false);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -19,21 +19,18 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            static CrossServerTextChannel()
 | 
			
		||||
            {
 | 
			
		||||
                _log = LogManager.GetCurrentClassLogger();
 | 
			
		||||
                NadekoBot.Client.MessageReceived += (imsg) =>
 | 
			
		||||
                NadekoBot.Client.MessageReceived += async (imsg) =>
 | 
			
		||||
                {
 | 
			
		||||
                    if (imsg.Author.IsBot)
 | 
			
		||||
                        return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                    var msg = imsg as IUserMessage;
 | 
			
		||||
                    if (msg == null)
 | 
			
		||||
                        return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                    var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
                    if (channel == null)
 | 
			
		||||
                        return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                    Task.Run(async () =>
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        if (imsg.Author.IsBot)
 | 
			
		||||
                            return;
 | 
			
		||||
                        var msg = imsg as IUserMessage;
 | 
			
		||||
                        if (msg == null)
 | 
			
		||||
                            return;
 | 
			
		||||
                        var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
                        if (channel == null)
 | 
			
		||||
                            return;
 | 
			
		||||
                        if (msg.Author.Id == NadekoBot.Client.GetCurrentUser().Id) return;
 | 
			
		||||
                        foreach (var subscriber in Subscribers)
 | 
			
		||||
                        {
 | 
			
		||||
@@ -45,8 +42,10 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                                try { await chan.SendMessageAsync(GetText(channel.Guild, channel, (IGuildUser)msg.Author, msg)).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    });
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (Exception ex) {
 | 
			
		||||
                        _log.Warn(ex);
 | 
			
		||||
                    }
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -86,67 +86,60 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                MuteCommands.UserUnmuted += MuteCommands_UserUnmuted;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private Task _client_UserVoiceStateUpdated_TTS(IUser iusr, IVoiceState before, IVoiceState after)
 | 
			
		||||
            private async void _client_UserVoiceStateUpdated_TTS(IUser iusr, IVoiceState before, IVoiceState after)
 | 
			
		||||
            {
 | 
			
		||||
                var usr = iusr as IGuildUser;
 | 
			
		||||
                if (usr == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                var beforeVch = before.VoiceChannel;
 | 
			
		||||
                var afterVch = after.VoiceChannel;
 | 
			
		||||
 | 
			
		||||
                if (beforeVch == afterVch)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                LogSetting logSetting;
 | 
			
		||||
                if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out logSetting)
 | 
			
		||||
                    || (logSetting.LogVoicePresenceTTSId == null))
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                ITextChannel logChannel;
 | 
			
		||||
                if ((logChannel = TryGetLogChannel(usr.Guild, logSetting, LogType.VoicePresenceTTS)) == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                string str = null;
 | 
			
		||||
                if (beforeVch?.Guild == afterVch?.Guild)
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    str = $"{usr.Username} moved from {beforeVch.Name} to {afterVch.Name}";
 | 
			
		||||
                }
 | 
			
		||||
                else if (beforeVch == null)
 | 
			
		||||
                {
 | 
			
		||||
                    str = $"{usr.Username} has joined {afterVch.Name}";
 | 
			
		||||
                }
 | 
			
		||||
                else if (afterVch == null)
 | 
			
		||||
                {
 | 
			
		||||
                    str = $"{usr.Username} has left {beforeVch.Name}";
 | 
			
		||||
                }
 | 
			
		||||
                    var usr = iusr as IGuildUser;
 | 
			
		||||
                    if (usr == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                Task.Run(async () =>
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    var beforeVch = before.VoiceChannel;
 | 
			
		||||
                    var afterVch = after.VoiceChannel;
 | 
			
		||||
 | 
			
		||||
                    if (beforeVch == afterVch)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out logSetting)
 | 
			
		||||
                        || (logSetting.LogVoicePresenceTTSId == null))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    ITextChannel logChannel;
 | 
			
		||||
                    if ((logChannel = TryGetLogChannel(usr.Guild, logSetting, LogType.VoicePresenceTTS)) == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    string str = null;
 | 
			
		||||
                    if (beforeVch?.Guild == afterVch?.Guild)
 | 
			
		||||
                    {
 | 
			
		||||
                        var toDelete = await logChannel.SendMessageAsync(str, true).ConfigureAwait(false);
 | 
			
		||||
                        toDelete.DeleteAfter(5);
 | 
			
		||||
                        str = $"{usr.Username} moved from {beforeVch.Name} to {afterVch.Name}";
 | 
			
		||||
                    }
 | 
			
		||||
                    catch { }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
                    else if (beforeVch == null)
 | 
			
		||||
                    {
 | 
			
		||||
                        str = $"{usr.Username} has joined {afterVch.Name}";
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (afterVch == null)
 | 
			
		||||
                    {
 | 
			
		||||
                        str = $"{usr.Username} has left {beforeVch.Name}";
 | 
			
		||||
                    }
 | 
			
		||||
                    var toDelete = await logChannel.SendMessageAsync(str, true).ConfigureAwait(false);
 | 
			
		||||
                    toDelete.DeleteAfter(5);
 | 
			
		||||
                }
 | 
			
		||||
                catch { }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private Task MuteCommands_UserMuted(IGuildUser usr, MuteCommands.MuteType muteType)
 | 
			
		||||
            private async void MuteCommands_UserMuted(IGuildUser usr, MuteCommands.MuteType muteType)
 | 
			
		||||
            {
 | 
			
		||||
                LogSetting logSetting;
 | 
			
		||||
                if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out logSetting)
 | 
			
		||||
                    || (logSetting.UserMutedId == null))
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                ITextChannel logChannel;
 | 
			
		||||
                if ((logChannel = TryGetLogChannel(usr.Guild, logSetting, LogType.UserMuted)) == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                var task = Task.Run(async () =>
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out logSetting)
 | 
			
		||||
                        || (logSetting.UserMutedId == null))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    ITextChannel logChannel;
 | 
			
		||||
                    if ((logChannel = TryGetLogChannel(usr.Guild, logSetting, LogType.UserMuted)) == null)
 | 
			
		||||
                        return;
 | 
			
		||||
                    string mutes = "";
 | 
			
		||||
                    switch (muteType)
 | 
			
		||||
                    {
 | 
			
		||||
@@ -160,25 +153,24 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                            mutes = "text and voice chat";
 | 
			
		||||
                            break;
 | 
			
		||||
                    }
 | 
			
		||||
                    try { await logChannel.SendMessageAsync($"‼️🕕`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__🔇 **| User muted from the {mutes}. |** 🆔 `{usr.Id}`").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
                    await logChannel.SendMessageAsync($"‼️🕕`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__🔇 **| User muted from the {mutes}. |** 🆔 `{usr.Id}`").ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private Task MuteCommands_UserUnmuted(IGuildUser usr, MuteCommands.MuteType muteType)
 | 
			
		||||
            private async void MuteCommands_UserUnmuted(IGuildUser usr, MuteCommands.MuteType muteType)
 | 
			
		||||
            {
 | 
			
		||||
                LogSetting logSetting;
 | 
			
		||||
                if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out logSetting)
 | 
			
		||||
                    || (logSetting.UserMutedId == null))
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                ITextChannel logChannel;
 | 
			
		||||
                if ((logChannel = TryGetLogChannel(usr.Guild, logSetting, LogType.UserMuted)) == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                var task = Task.Run(async () =>
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out logSetting)
 | 
			
		||||
                        || (logSetting.UserMutedId == null))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    ITextChannel logChannel;
 | 
			
		||||
                    if ((logChannel = TryGetLogChannel(usr.Guild, logSetting, LogType.UserMuted)) == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    string mutes = "";
 | 
			
		||||
                    switch (muteType)
 | 
			
		||||
                    {
 | 
			
		||||
@@ -192,392 +184,373 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                            mutes = "text and voice chat";
 | 
			
		||||
                            break;
 | 
			
		||||
                    }
 | 
			
		||||
                    try { await logChannel.SendMessageAsync($"‼️🕕`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__🔊 **| User unmuted from the {mutes}. |** 🆔 `{usr.Id}`").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
                    await logChannel.SendMessageAsync($"‼️🕕`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__🔊 **| User unmuted from the {mutes}. |** 🆔 `{usr.Id}`").ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public static async Task TriggeredAntiProtection(IGuildUser[] users, PunishmentAction action, ProtectionType protection)
 | 
			
		||||
            {
 | 
			
		||||
                if (users.Length == 0)
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                LogSetting logSetting;
 | 
			
		||||
                if (!GuildLogSettings.TryGetValue(users.First().Guild.Id, out logSetting)
 | 
			
		||||
                    || (logSetting.LogOtherId == null))
 | 
			
		||||
                    return;
 | 
			
		||||
                ITextChannel logChannel;
 | 
			
		||||
                if ((logChannel = TryGetLogChannel(users.First().Guild, logSetting, LogType.Other)) == null)
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                var punishment = "";
 | 
			
		||||
                if (action == PunishmentAction.Mute)
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    punishment = "🔇 MUTED";
 | 
			
		||||
                    //punishment = "MUTED";
 | 
			
		||||
                }
 | 
			
		||||
                else if (action == PunishmentAction.Kick)
 | 
			
		||||
                {
 | 
			
		||||
                    punishment = "☣ SOFT-BANNED (KICKED)";
 | 
			
		||||
                    //punishment = "KICKED";
 | 
			
		||||
                }
 | 
			
		||||
                else if (action == PunishmentAction.Ban)
 | 
			
		||||
                {
 | 
			
		||||
                    punishment = "⛔️ BANNED";
 | 
			
		||||
                    //punishment = "BANNED";
 | 
			
		||||
                }
 | 
			
		||||
                await logChannel.SendMessageAsync(String.Join("\n", users.Select(user => $"‼️ {Format.Bold(user.ToString())} got **{punishment}** due to __**{protection}**__ protection on **{user.Guild.Name}** server.")))
 | 
			
		||||
                //await logChannel.SendMessageAsync(String.Join("\n",users.Select(user=>$"{Format.Bold(user.ToString())} was **{punishment}** due to `{protection}` protection on **{user.Guild.Name}** server.")))
 | 
			
		||||
                                .ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
                    if (users.Length == 0)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
            private Task _client_UserUpdated(IGuildUser before, IGuildUser after)
 | 
			
		||||
            {
 | 
			
		||||
                LogSetting logSetting;
 | 
			
		||||
                if (!GuildLogSettings.TryGetValue(before.Guild.Id, out logSetting)
 | 
			
		||||
                    || (logSetting.UserUpdatedId == null))
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(users.First().Guild.Id, out logSetting)
 | 
			
		||||
                        || (logSetting.LogOtherId == null))
 | 
			
		||||
                        return;
 | 
			
		||||
                    ITextChannel logChannel;
 | 
			
		||||
                    if ((logChannel = TryGetLogChannel(users.First().Guild, logSetting, LogType.Other)) == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                ITextChannel logChannel;
 | 
			
		||||
                if ((logChannel = TryGetLogChannel(before.Guild, logSetting, LogType.UserUpdated)) == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                var task = Task.Run(async () =>
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    var punishment = "";
 | 
			
		||||
                    if (action == PunishmentAction.Mute)
 | 
			
		||||
                    {
 | 
			
		||||
                        string str = $"🕔`{prettyCurrentTime}`";
 | 
			
		||||
                        if (before.Username != after.Username)
 | 
			
		||||
                            //str += $"**Name Changed**`{before.Username}#{before.Discriminator}`\n\t\t`New:`{after.ToString()}`";
 | 
			
		||||
                            str += $"👤__**{before.Username}#{before.Discriminator}**__ **| Name Changed |** 🆔 `{before.Id}`\n\t\t`New:` **{after.ToString()}**";
 | 
			
		||||
                        else if (before.Nickname != after.Nickname)
 | 
			
		||||
                            str += $"👤__**{before.Username}#{before.Discriminator}**__ **| Nickname Changed |** 🆔 `{before.Id}`\n\t\t`Old:` **{before.Nickname}#{before.Discriminator}**\n\t\t`New:` **{after.Nickname}#{after.Discriminator}**";
 | 
			
		||||
                        //str += $"**Nickname Changed**`{before.Username}#{before.Discriminator}`\n\t\t`Old:` {before.Nickname}#{before.Discriminator}\n\t\t`New:` {after.Nickname}#{after.Discriminator}";
 | 
			
		||||
                        else if (before.AvatarUrl != after.AvatarUrl)
 | 
			
		||||
                            //str += $"**Avatar Changed**👤`{before.Username}#{before.Discriminator}`\n\t {await _google.ShortenUrl(before.AvatarUrl)} `=>` {await _google.ShortenUrl(after.AvatarUrl)}";
 | 
			
		||||
                            str += $"👤__**{before.Username}#{before.Discriminator}**__ **| Avatar Changed |** 🆔 `{before.Id}`\n\t🖼 {await _google.ShortenUrl(before.AvatarUrl)} `=>` {await _google.ShortenUrl(after.AvatarUrl)}";
 | 
			
		||||
                        else if (!before.Roles.SequenceEqual(after.Roles))
 | 
			
		||||
                        {
 | 
			
		||||
                            if (before.Roles.Count() < after.Roles.Count())
 | 
			
		||||
                            {
 | 
			
		||||
                                var diffRoles = after.Roles.Where(r => !before.Roles.Contains(r)).Select(r => "**" + r.Name + "**");
 | 
			
		||||
                                //str += $"**User's Roles changed ⚔➕**👤`{before.ToString()}`\n\tNow has {string.Join(", ", diffRoles)} role.";
 | 
			
		||||
                                str += $"👤__**{before.ToString()}**__ **| User's Role Added |** 🆔 `{before.Id}`\n\t✅ {string.Join(", ", diffRoles).SanitizeMentions()}\n\t\t⚔ **`{string.Join(", ", after.Roles.Select(r => r.Name)).SanitizeMentions()}`** ⚔";
 | 
			
		||||
                            }
 | 
			
		||||
                            else if (before.Roles.Count() > after.Roles.Count())
 | 
			
		||||
                            {
 | 
			
		||||
                                var diffRoles = before.Roles.Where(r => !after.Roles.Contains(r)).Select(r => "**" + r.Name + "**");
 | 
			
		||||
                                //str += $"**User's Roles changed **`{before.ToString()}`\n\tNo longer has {string.Join(", ", diffRoles)} role.";
 | 
			
		||||
                                str += $"👤__**{before.ToString()}**__ **| User's Role Removed |** 🆔 `{before.Id}`\n\t🚮 {string.Join(", ", diffRoles).SanitizeMentions()}\n\t\t⚔ **`{string.Join(", ", after.Roles.Select(r => r.Name)).SanitizeMentions()}`** ⚔";
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                            return;
 | 
			
		||||
                        try { await logChannel.SendMessageAsync(str).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
                        punishment = "🔇 MUTED";
 | 
			
		||||
                        //punishment = "MUTED";
 | 
			
		||||
                    }
 | 
			
		||||
                    catch { }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
                    else if (action == PunishmentAction.Kick)
 | 
			
		||||
                    {
 | 
			
		||||
                        punishment = "☣ SOFT-BANNED (KICKED)";
 | 
			
		||||
                        //punishment = "KICKED";
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (action == PunishmentAction.Ban)
 | 
			
		||||
                    {
 | 
			
		||||
                        punishment = "⛔️ BANNED";
 | 
			
		||||
                        //punishment = "BANNED";
 | 
			
		||||
                    }
 | 
			
		||||
                    await logChannel.SendMessageAsync(String.Join("\n", users.Select(user => $"‼️ {Format.Bold(user.ToString())} got **{punishment}** due to __**{protection}**__ protection on **{user.Guild.Name}** server.")))
 | 
			
		||||
                                    //await logChannel.SendMessageAsync(String.Join("\n",users.Select(user=>$"{Format.Bold(user.ToString())} was **{punishment}** due to `{protection}` protection on **{user.Guild.Name}** server.")))
 | 
			
		||||
                                    .ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private Task _client_ChannelUpdated(IChannel cbefore, IChannel cafter)
 | 
			
		||||
            private async void _client_UserUpdated(IGuildUser before, IGuildUser after)
 | 
			
		||||
            {
 | 
			
		||||
                var before = cbefore as IGuildChannel;
 | 
			
		||||
                if (before == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                var after = (IGuildChannel)cafter;
 | 
			
		||||
 | 
			
		||||
                LogSetting logSetting;
 | 
			
		||||
                if (!GuildLogSettings.TryGetValue(before.Guild.Id, out logSetting)
 | 
			
		||||
                    || (logSetting.ChannelUpdatedId == null)
 | 
			
		||||
                    || logSetting.IgnoredChannels.Any(ilc => ilc.ChannelId == after.Id))
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                ITextChannel logChannel;
 | 
			
		||||
                if ((logChannel = TryGetLogChannel(before.Guild, logSetting, LogType.ChannelUpdated)) == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                var task = Task.Run(async () =>
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(before.Guild.Id, out logSetting)
 | 
			
		||||
                        || (logSetting.UserUpdatedId == null))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    ITextChannel logChannel;
 | 
			
		||||
                    if ((logChannel = TryGetLogChannel(before.Guild, logSetting, LogType.UserUpdated)) == null)
 | 
			
		||||
                        return;
 | 
			
		||||
                    string str = $"🕔`{prettyCurrentTime}`";
 | 
			
		||||
                    if (before.Username != after.Username)
 | 
			
		||||
                        //str += $"**Name Changed**`{before.Username}#{before.Discriminator}`\n\t\t`New:`{after.ToString()}`";
 | 
			
		||||
                        str += $"👤__**{before.Username}#{before.Discriminator}**__ **| Name Changed |** 🆔 `{before.Id}`\n\t\t`New:` **{after.ToString()}**";
 | 
			
		||||
                    else if (before.Nickname != after.Nickname)
 | 
			
		||||
                        str += $"👤__**{before.Username}#{before.Discriminator}**__ **| Nickname Changed |** 🆔 `{before.Id}`\n\t\t`Old:` **{before.Nickname}#{before.Discriminator}**\n\t\t`New:` **{after.Nickname}#{after.Discriminator}**";
 | 
			
		||||
                    //str += $"**Nickname Changed**`{before.Username}#{before.Discriminator}`\n\t\t`Old:` {before.Nickname}#{before.Discriminator}\n\t\t`New:` {after.Nickname}#{after.Discriminator}";
 | 
			
		||||
                    else if (before.AvatarUrl != after.AvatarUrl)
 | 
			
		||||
                        //str += $"**Avatar Changed**👤`{before.Username}#{before.Discriminator}`\n\t {await _google.ShortenUrl(before.AvatarUrl)} `=>` {await _google.ShortenUrl(after.AvatarUrl)}";
 | 
			
		||||
                        str += $"👤__**{before.Username}#{before.Discriminator}**__ **| Avatar Changed |** 🆔 `{before.Id}`\n\t🖼 {await _google.ShortenUrl(before.AvatarUrl)} `=>` {await _google.ShortenUrl(after.AvatarUrl)}";
 | 
			
		||||
                    else if (!before.Roles.SequenceEqual(after.Roles))
 | 
			
		||||
                    {
 | 
			
		||||
                        if (before.Name != after.Name)
 | 
			
		||||
                            //await logChannel.SendMessageAsync($@"`{prettyCurrentTime}` **Channel Name Changed** `#{after.Name}` ({after.Id})
 | 
			
		||||
                            await logChannel.SendMessageAsync($@"🕓`{prettyCurrentTime}`ℹ️ **| Channel Name Changed |** #⃣ `{after.Name} ({after.Id})`
 | 
			
		||||
                        if (before.Roles.Count() < after.Roles.Count())
 | 
			
		||||
                        {
 | 
			
		||||
                            var diffRoles = after.Roles.Where(r => !before.Roles.Contains(r)).Select(r => "**" + r.Name + "**");
 | 
			
		||||
                            //str += $"**User's Roles changed ⚔➕**👤`{before.ToString()}`\n\tNow has {string.Join(", ", diffRoles)} role.";
 | 
			
		||||
                            str += $"👤__**{before.ToString()}**__ **| User's Role Added |** 🆔 `{before.Id}`\n\t✅ {string.Join(", ", diffRoles).SanitizeMentions()}\n\t\t⚔ **`{string.Join(", ", after.Roles.Select(r => r.Name)).SanitizeMentions()}`** ⚔";
 | 
			
		||||
                        }
 | 
			
		||||
                        else if (before.Roles.Count() > after.Roles.Count())
 | 
			
		||||
                        {
 | 
			
		||||
                            var diffRoles = before.Roles.Where(r => !after.Roles.Contains(r)).Select(r => "**" + r.Name + "**");
 | 
			
		||||
                            //str += $"**User's Roles changed **`{before.ToString()}`\n\tNo longer has {string.Join(", ", diffRoles)} role.";
 | 
			
		||||
                            str += $"👤__**{before.ToString()}**__ **| User's Role Removed |** 🆔 `{before.Id}`\n\t🚮 {string.Join(", ", diffRoles).SanitizeMentions()}\n\t\t⚔ **`{string.Join(", ", after.Roles.Select(r => r.Name)).SanitizeMentions()}`** ⚔";
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                        return;
 | 
			
		||||
                    try { await logChannel.SendMessageAsync(str).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private async void _client_ChannelUpdated(IChannel cbefore, IChannel cafter)
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    var before = cbefore as IGuildChannel;
 | 
			
		||||
                    if (before == null)
 | 
			
		||||
                        return;
 | 
			
		||||
                    var after = (IGuildChannel)cafter;
 | 
			
		||||
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(before.Guild.Id, out logSetting)
 | 
			
		||||
                        || (logSetting.ChannelUpdatedId == null)
 | 
			
		||||
                        || logSetting.IgnoredChannels.Any(ilc => ilc.ChannelId == after.Id))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    ITextChannel logChannel;
 | 
			
		||||
                    if ((logChannel = TryGetLogChannel(before.Guild, logSetting, LogType.ChannelUpdated)) == null)
 | 
			
		||||
                        return;
 | 
			
		||||
                    if (before.Name != after.Name)
 | 
			
		||||
                        //await logChannel.SendMessageAsync($@"`{prettyCurrentTime}` **Channel Name Changed** `#{after.Name}` ({after.Id})
 | 
			
		||||
                        await logChannel.SendMessageAsync($@"🕓`{prettyCurrentTime}`ℹ️ **| Channel Name Changed |** #⃣ `{after.Name} ({after.Id})`
 | 
			
		||||
    `Old:` {before.Name}
 | 
			
		||||
    **`New:`** {after.Name}").ConfigureAwait(false);
 | 
			
		||||
                        else if ((before as ITextChannel).Topic != (after as ITextChannel).Topic)
 | 
			
		||||
                            //await logChannel.SendMessageAsync($@"`{prettyCurrentTime}` **Channel Topic Changed** `#{after.Name}` ({after.Id})
 | 
			
		||||
                            await logChannel.SendMessageAsync($@"🕘`{prettyCurrentTime}`ℹ️ **| Channel Topic Changed |** #⃣ `{after.Name} ({after.Id})`
 | 
			
		||||
                    else if ((before as ITextChannel).Topic != (after as ITextChannel).Topic)
 | 
			
		||||
                        //await logChannel.SendMessageAsync($@"`{prettyCurrentTime}` **Channel Topic Changed** `#{after.Name}` ({after.Id})
 | 
			
		||||
                        await logChannel.SendMessageAsync($@"🕘`{prettyCurrentTime}`ℹ️ **| Channel Topic Changed |** #⃣ `{after.Name} ({after.Id})`
 | 
			
		||||
    `Old:` {((ITextChannel)before).Topic}
 | 
			
		||||
    **`New:`** {((ITextChannel)after).Topic}").ConfigureAwait(false);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch { }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private Task _client_ChannelDestroyed(IChannel ich)
 | 
			
		||||
            {
 | 
			
		||||
                var ch = ich as IGuildChannel;
 | 
			
		||||
                if (ch == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                LogSetting logSetting;
 | 
			
		||||
                if (!GuildLogSettings.TryGetValue(ch.Guild.Id, out logSetting)
 | 
			
		||||
                    || (logSetting.ChannelDestroyedId == null)
 | 
			
		||||
                    || logSetting.IgnoredChannels.Any(ilc => ilc.ChannelId == ch.Id))
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                ITextChannel logChannel;
 | 
			
		||||
                if ((logChannel = TryGetLogChannel(ch.Guild, logSetting, LogType.ChannelDestroyed)) == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                var task = Task.Run(async () =>
 | 
			
		||||
                {
 | 
			
		||||
                    try { await logChannel.SendMessageAsync($"🕕`{prettyCurrentTime}`🗑 **| {(ch is IVoiceChannel ? "Voice" : "Text")} Channel Deleted #⃣ {ch.Name}** `({ch.Id})`").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private Task _client_ChannelCreated(IChannel ich)
 | 
			
		||||
            {
 | 
			
		||||
                var ch = ich as IGuildChannel;
 | 
			
		||||
                if (ch == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                LogSetting logSetting;
 | 
			
		||||
                if (!GuildLogSettings.TryGetValue(ch.Guild.Id, out logSetting)
 | 
			
		||||
                    || (logSetting.ChannelCreatedId == null))
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                ITextChannel logChannel;
 | 
			
		||||
                if ((logChannel = TryGetLogChannel(ch.Guild, logSetting, LogType.ChannelCreated)) == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                var task = Task.Run(async () =>
 | 
			
		||||
                {
 | 
			
		||||
                    try { await logChannel.SendMessageAsync($"🕓`{prettyCurrentTime}`🆕 **| {(ch is IVoiceChannel ? "Voice" : "Text")} Channel Created: #⃣ {ch.Name}** `({ch.Id})`").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private Task _client_UserVoiceStateUpdated(IUser iusr, IVoiceState before, IVoiceState after)
 | 
			
		||||
            {
 | 
			
		||||
                var usr = iusr as IGuildUser;
 | 
			
		||||
                if (usr == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                var beforeVch = before.VoiceChannel;
 | 
			
		||||
                var afterVch = after.VoiceChannel;
 | 
			
		||||
 | 
			
		||||
                if (beforeVch == afterVch)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                LogSetting logSetting;
 | 
			
		||||
                if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out logSetting)
 | 
			
		||||
                    || (logSetting.LogVoicePresenceId == null))
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                ITextChannel logChannel;
 | 
			
		||||
                if ((logChannel = TryGetLogChannel(usr.Guild, logSetting, LogType.VoicePresence)) == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                string str = null;
 | 
			
		||||
                if (beforeVch?.Guild == afterVch?.Guild)
 | 
			
		||||
                {
 | 
			
		||||
                    str = $"🎙`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__ moved from **{beforeVch.Name}** to **{afterVch.Name}** voice channel.";
 | 
			
		||||
                }
 | 
			
		||||
                else if (beforeVch == null)
 | 
			
		||||
                catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private async void _client_ChannelDestroyed(IChannel ich)
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    str = $"🎙`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__ has joined **{afterVch.Name}** voice channel.";
 | 
			
		||||
                    var ch = ich as IGuildChannel;
 | 
			
		||||
                    if (ch == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(ch.Guild.Id, out logSetting)
 | 
			
		||||
                        || (logSetting.ChannelDestroyedId == null)
 | 
			
		||||
                        || logSetting.IgnoredChannels.Any(ilc => ilc.ChannelId == ch.Id))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    ITextChannel logChannel;
 | 
			
		||||
                    if ((logChannel = TryGetLogChannel(ch.Guild, logSetting, LogType.ChannelDestroyed)) == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    await logChannel.SendMessageAsync($"🕕`{prettyCurrentTime}`🗑 **| {(ch is IVoiceChannel ? "Voice" : "Text")} Channel Deleted #⃣ {ch.Name}** `({ch.Id})`").ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                else if (afterVch == null)
 | 
			
		||||
                catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private async void _client_ChannelCreated(IChannel ich)
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    str = $"🎙`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__ has left **{beforeVch.Name}** voice channel.";
 | 
			
		||||
                    var ch = ich as IGuildChannel;
 | 
			
		||||
                    if (ch == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(ch.Guild.Id, out logSetting)
 | 
			
		||||
                        || (logSetting.ChannelCreatedId == null))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    ITextChannel logChannel;
 | 
			
		||||
                    if ((logChannel = TryGetLogChannel(ch.Guild, logSetting, LogType.ChannelCreated)) == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    await logChannel.SendMessageAsync($"🕓`{prettyCurrentTime}`🆕 **| {(ch is IVoiceChannel ? "Voice" : "Text")} Channel Created: #⃣ {ch.Name}** `({ch.Id})`").ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                if (str != null)
 | 
			
		||||
                    UserPresenceUpdates.AddOrUpdate(logChannel, new List<string>() { str }, (id, list) => { list.Add(str); return list; });
 | 
			
		||||
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
                catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private Task _client_UserPresenceUpdated(IGuildUser usr, IPresence before, IPresence after)
 | 
			
		||||
            private async void _client_UserVoiceStateUpdated(IUser iusr, IVoiceState before, IVoiceState after) => await Task.Run(() =>
 | 
			
		||||
            {
 | 
			
		||||
                LogSetting logSetting;
 | 
			
		||||
                if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out logSetting)
 | 
			
		||||
                    || (logSetting.LogUserPresenceId == null)
 | 
			
		||||
                    || before.Status == after.Status)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                ITextChannel logChannel;
 | 
			
		||||
                if ((logChannel = TryGetLogChannel(usr.Guild, logSetting, LogType.UserPresence)) == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                string str;
 | 
			
		||||
                if (before.Status != after.Status)
 | 
			
		||||
                    str = $"🔵`{prettyCurrentTime}`👤__**{usr.Username}**__ is now **{after.Status}**.";
 | 
			
		||||
                else
 | 
			
		||||
                    str = $"👾`{prettyCurrentTime}`👤__**{usr.Username}**__ is now playing **{after.Game}**.";
 | 
			
		||||
 | 
			
		||||
                UserPresenceUpdates.AddOrUpdate(logChannel, new List<string>() { str }, (id, list) => { list.Add(str); return list; });
 | 
			
		||||
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private Task _client_UserLeft(IGuildUser usr)
 | 
			
		||||
            {
 | 
			
		||||
                LogSetting logSetting;
 | 
			
		||||
                if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out logSetting)
 | 
			
		||||
                    || (logSetting.UserLeftId == null))
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                ITextChannel logChannel;
 | 
			
		||||
                if ((logChannel = TryGetLogChannel(usr.Guild, logSetting, LogType.UserLeft)) == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                var task = Task.Run(async () =>
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    try { await logChannel.SendMessageAsync($"❗️🕛`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__❌ **| USER LEFT |** 🆔 `{usr.Id}`").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
                });
 | 
			
		||||
                    var usr = iusr as IGuildUser;
 | 
			
		||||
                    if (usr == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            }
 | 
			
		||||
                    var beforeVch = before.VoiceChannel;
 | 
			
		||||
                    var afterVch = after.VoiceChannel;
 | 
			
		||||
 | 
			
		||||
            private Task _client_UserJoined(IGuildUser usr)
 | 
			
		||||
            {
 | 
			
		||||
                LogSetting logSetting;
 | 
			
		||||
                if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out logSetting)
 | 
			
		||||
                    || (logSetting.UserJoinedId == null))
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                    if (beforeVch == afterVch)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                ITextChannel logChannel;
 | 
			
		||||
                if ((logChannel = TryGetLogChannel(usr.Guild, logSetting, LogType.UserJoined)) == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out logSetting)
 | 
			
		||||
                        || (logSetting.LogVoicePresenceId == null))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                var task = Task.Run(async () =>
 | 
			
		||||
                {
 | 
			
		||||
                    try { await logChannel.SendMessageAsync($"❕🕓`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__✅ **| USER JOINED |** 🆔 `{usr.Id}`").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
                });
 | 
			
		||||
                    ITextChannel logChannel;
 | 
			
		||||
                    if ((logChannel = TryGetLogChannel(usr.Guild, logSetting, LogType.VoicePresence)) == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private Task _client_UserUnbanned(IUser usr, IGuild guild)
 | 
			
		||||
            {
 | 
			
		||||
                LogSetting logSetting;
 | 
			
		||||
                if (!GuildLogSettings.TryGetValue(guild.Id, out logSetting)
 | 
			
		||||
                    || (logSetting.UserUnbannedId == null))
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                ITextChannel logChannel;
 | 
			
		||||
                if ((logChannel = TryGetLogChannel(guild, logSetting, LogType.UserUnbanned)) == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                var task = Task.Run(async () =>
 | 
			
		||||
                {
 | 
			
		||||
                    try { await logChannel.SendMessageAsync($"❕🕘`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__♻️ **| USER UN-BANNED |** 🆔 `{usr.Id}`").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private Task _client_UserBanned(IUser usr, IGuild guild)
 | 
			
		||||
            {
 | 
			
		||||
                LogSetting logSetting;
 | 
			
		||||
                if (!GuildLogSettings.TryGetValue(guild.Id, out logSetting)
 | 
			
		||||
                    || (logSetting.UserBannedId == null))
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                ITextChannel logChannel;
 | 
			
		||||
                if ((logChannel = TryGetLogChannel(guild, logSetting, LogType.UserBanned)) == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                var task = Task.Run(async () =>
 | 
			
		||||
                {
 | 
			
		||||
                    try { await logChannel.SendMessageAsync($"‼️🕕`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__🚫 **| USER BANNED |** 🆔 `{usr.Id}`").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
                });
 | 
			
		||||
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private Task _client_MessageDeleted(ulong arg1, Optional<IMessage> imsg)
 | 
			
		||||
            {
 | 
			
		||||
                var msg = (imsg.IsSpecified ? imsg.Value : null) as IUserMessage;
 | 
			
		||||
                if (msg == null || msg.IsAuthor())
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                var channel = msg.Channel as ITextChannel;
 | 
			
		||||
                if (channel == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                LogSetting logSetting;
 | 
			
		||||
                if (!GuildLogSettings.TryGetValue(channel.Guild.Id, out logSetting)
 | 
			
		||||
                    || (logSetting.MessageDeletedId == null)
 | 
			
		||||
                    || logSetting.IgnoredChannels.Any(ilc => ilc.ChannelId == channel.Id))
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                ITextChannel logChannel;
 | 
			
		||||
                if ((logChannel = TryGetLogChannel(channel.Guild, logSetting, LogType.MessageDeleted)) == null || logChannel.Id == msg.Id)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                var task = Task.Run(async () =>
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    string str = null;
 | 
			
		||||
                    if (beforeVch?.Guild == afterVch?.Guild)
 | 
			
		||||
                    {
 | 
			
		||||
                        var str = $@"🕔`{prettyCurrentTime}`👤__**{msg.Author.Username}#{msg.Author.Discriminator}**__ **| Deleted Message |** 🆔 `{msg.Author.Id}` #⃣ `{channel.Name}`
 | 
			
		||||
🗑 {msg.Resolve(userHandling: UserMentionHandling.NameAndDiscriminator)}";
 | 
			
		||||
                        if (msg.Attachments.Any())
 | 
			
		||||
                            str += $"{Environment.NewLine}📎 {string.Join(", ", msg.Attachments.Select(a => a.ProxyUrl))}";
 | 
			
		||||
                        await logChannel.SendMessageAsync(str.SanitizeMentions()).ConfigureAwait(false);
 | 
			
		||||
                        str = $"🎙`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__ moved from **{beforeVch.Name}** to **{afterVch.Name}** voice channel.";
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
                });
 | 
			
		||||
                    else if (beforeVch == null)
 | 
			
		||||
                    {
 | 
			
		||||
                        str = $"🎙`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__ has joined **{afterVch.Name}** voice channel.";
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (afterVch == null)
 | 
			
		||||
                    {
 | 
			
		||||
                        str = $"🎙`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__ has left **{beforeVch.Name}** voice channel.";
 | 
			
		||||
                    }
 | 
			
		||||
                    if (str != null)
 | 
			
		||||
                        UserPresenceUpdates.AddOrUpdate(logChannel, new List<string>() { str }, (id, list) => { list.Add(str); return list; });
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex)
 | 
			
		||||
                {
 | 
			
		||||
                    _log.Warn(ex);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            private async void _client_UserPresenceUpdated(IGuildUser usr, IPresence before, IPresence after) => await Task.Run(() =>
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out logSetting)
 | 
			
		||||
                        || (logSetting.LogUserPresenceId == null)
 | 
			
		||||
                        || before.Status == after.Status)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    ITextChannel logChannel;
 | 
			
		||||
                    if ((logChannel = TryGetLogChannel(usr.Guild, logSetting, LogType.UserPresence)) == null)
 | 
			
		||||
                        return;
 | 
			
		||||
                    string str;
 | 
			
		||||
                    if (before.Status != after.Status)
 | 
			
		||||
                        str = $"🔵`{prettyCurrentTime}`👤__**{usr.Username}**__ is now **{after.Status}**.";
 | 
			
		||||
                    else
 | 
			
		||||
                        str = $"👾`{prettyCurrentTime}`👤__**{usr.Username}**__ is now playing **{after.Game}**.";
 | 
			
		||||
 | 
			
		||||
                    UserPresenceUpdates.AddOrUpdate(logChannel, new List<string>() { str }, (id, list) => { list.Add(str); return list; });
 | 
			
		||||
                }
 | 
			
		||||
                catch { }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            private async void _client_UserLeft(IGuildUser usr)
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out logSetting)
 | 
			
		||||
                        || (logSetting.UserLeftId == null))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    ITextChannel logChannel;
 | 
			
		||||
                    if ((logChannel = TryGetLogChannel(usr.Guild, logSetting, LogType.UserLeft)) == null)
 | 
			
		||||
                        return;
 | 
			
		||||
                    await logChannel.SendMessageAsync($"❗️🕛`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__❌ **| USER LEFT |** 🆔 `{usr.Id}`").ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch { }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private Task _client_MessageUpdated(Optional<IMessage> optmsg, IMessage imsg2)
 | 
			
		||||
            private async void _client_UserJoined(IGuildUser usr)
 | 
			
		||||
            {
 | 
			
		||||
                var after = imsg2 as IUserMessage;
 | 
			
		||||
                if (after == null || after.IsAuthor())
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                var before = (optmsg.IsSpecified ? optmsg.Value : null) as IUserMessage;
 | 
			
		||||
                if (before == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                var channel = after.Channel as ITextChannel;
 | 
			
		||||
                if (channel == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                if (before.Content == after.Content)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                LogSetting logSetting;
 | 
			
		||||
                if (!GuildLogSettings.TryGetValue(channel.Guild.Id, out logSetting)
 | 
			
		||||
                    || (logSetting.MessageUpdatedId == null)
 | 
			
		||||
                    || logSetting.IgnoredChannels.Any(ilc => ilc.ChannelId == channel.Id))
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                ITextChannel logChannel;
 | 
			
		||||
                if ((logChannel = TryGetLogChannel(channel.Guild, logSetting, LogType.MessageUpdated)) == null || logChannel.Id == after.Channel.Id)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                var task = Task.Run(async () =>
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    //try { await logChannel.SendMessageAsync($@"🕔`{prettyCurrentTime}` **Message** 📝 `#{channel.Name}`
 | 
			
		||||
                    //👤`{before.Author.Username}`
 | 
			
		||||
                    try { await logChannel.SendMessageAsync($@"🕔`{prettyCurrentTime}`👤__**{before.Author.Username}#{before.Author.Discriminator}**__ **| 📝 Edited Message |** 🆔 `{before.Author.Id}` #⃣ `{channel.Name}`
 | 
			
		||||
        `Old:` {before.Resolve(userHandling: UserMentionHandling.NameAndDiscriminator).SanitizeMentions()}
 | 
			
		||||
        **`New:`** {after.Resolve(userHandling: UserMentionHandling.NameAndDiscriminator).SanitizeMentions()}").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
                });
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(usr.Guild.Id, out logSetting)
 | 
			
		||||
                        || (logSetting.UserJoinedId == null))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
                    ITextChannel logChannel;
 | 
			
		||||
                    if ((logChannel = TryGetLogChannel(usr.Guild, logSetting, LogType.UserJoined)) == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    await logChannel.SendMessageAsync($"❕🕓`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__✅ **| USER JOINED |** 🆔 `{usr.Id}`").ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private async void _client_UserUnbanned(IUser usr, IGuild guild)
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(guild.Id, out logSetting)
 | 
			
		||||
                        || (logSetting.UserUnbannedId == null))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    ITextChannel logChannel;
 | 
			
		||||
                    if ((logChannel = TryGetLogChannel(guild, logSetting, LogType.UserUnbanned)) == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    await logChannel.SendMessageAsync($"❕🕘`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__♻️ **| USER UN-BANNED |** 🆔 `{usr.Id}`").ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private async void _client_UserBanned(IUser usr, IGuild guild)
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(guild.Id, out logSetting)
 | 
			
		||||
                        || (logSetting.UserBannedId == null))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    ITextChannel logChannel;
 | 
			
		||||
                    if ((logChannel = TryGetLogChannel(guild, logSetting, LogType.UserBanned)) == null)
 | 
			
		||||
                        return;
 | 
			
		||||
                    await logChannel.SendMessageAsync($"‼️🕕`{prettyCurrentTime}`👤__**{usr.Username}#{usr.Discriminator}**__🚫 **| USER BANNED |** 🆔 `{usr.Id}`").ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private async void _client_MessageDeleted(ulong arg1, Optional<IMessage> imsg)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    var msg = (imsg.IsSpecified ? imsg.Value : null) as IUserMessage;
 | 
			
		||||
                    if (msg == null || msg.IsAuthor())
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    var channel = msg.Channel as ITextChannel;
 | 
			
		||||
                    if (channel == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(channel.Guild.Id, out logSetting)
 | 
			
		||||
                        || (logSetting.MessageDeletedId == null)
 | 
			
		||||
                        || logSetting.IgnoredChannels.Any(ilc => ilc.ChannelId == channel.Id))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    ITextChannel logChannel;
 | 
			
		||||
                    if ((logChannel = TryGetLogChannel(channel.Guild, logSetting, LogType.MessageDeleted)) == null || logChannel.Id == msg.Id)
 | 
			
		||||
                        return;
 | 
			
		||||
                    var str = $@"🕔`{prettyCurrentTime}`👤__**{msg.Author.Username}#{msg.Author.Discriminator}**__ **| Deleted Message |** 🆔 `{msg.Author.Id}` #⃣ `{channel.Name}`
 | 
			
		||||
🗑 {msg.Resolve(userHandling: UserMentionHandling.NameAndDiscriminator)}";
 | 
			
		||||
                    if (msg.Attachments.Any())
 | 
			
		||||
                        str += $"{Environment.NewLine}📎 {string.Join(", ", msg.Attachments.Select(a => a.ProxyUrl))}";
 | 
			
		||||
                    await logChannel.SendMessageAsync(str.SanitizeMentions()).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private async void _client_MessageUpdated(Optional<IMessage> optmsg, IMessage imsg2)
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    var after = imsg2 as IUserMessage;
 | 
			
		||||
                    if (after == null || after.IsAuthor())
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    var before = (optmsg.IsSpecified ? optmsg.Value : null) as IUserMessage;
 | 
			
		||||
                    if (before == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    var channel = after.Channel as ITextChannel;
 | 
			
		||||
                    if (channel == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    if (before.Content == after.Content)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    LogSetting logSetting;
 | 
			
		||||
                    if (!GuildLogSettings.TryGetValue(channel.Guild.Id, out logSetting)
 | 
			
		||||
                        || (logSetting.MessageUpdatedId == null)
 | 
			
		||||
                        || logSetting.IgnoredChannels.Any(ilc => ilc.ChannelId == channel.Id))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    ITextChannel logChannel;
 | 
			
		||||
                    if ((logChannel = TryGetLogChannel(channel.Guild, logSetting, LogType.MessageUpdated)) == null || logChannel.Id == after.Channel.Id)
 | 
			
		||||
                        return;
 | 
			
		||||
                    await logChannel.SendMessageAsync($@"🕔`{prettyCurrentTime}`👤__**{before.Author.Username}#{before.Author.Discriminator}**__ **| 📝 Edited Message |** 🆔 `{before.Author.Id}` #⃣ `{channel.Name}`
 | 
			
		||||
        `Old:` {before.Resolve(userHandling: UserMentionHandling.NameAndDiscriminator).SanitizeMentions()}
 | 
			
		||||
        **`New:`** {after.Resolve(userHandling: UserMentionHandling.NameAndDiscriminator).SanitizeMentions()}").ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public enum LogType
 | 
			
		||||
 
 | 
			
		||||
@@ -24,8 +24,8 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
 | 
			
		||||
            private static ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> MutedUsers { get; } = new ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>>();
 | 
			
		||||
 | 
			
		||||
            public static event Func<IGuildUser, MuteType, Task> UserMuted = delegate { return Task.CompletedTask; };
 | 
			
		||||
            public static event Func<IGuildUser, MuteType, Task> UserUnmuted = delegate { return Task.CompletedTask; };
 | 
			
		||||
            public static event Action<IGuildUser, MuteType> UserMuted = delegate { };
 | 
			
		||||
            public static event Action<IGuildUser, MuteType> UserUnmuted = delegate { };
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            public enum MuteType {
 | 
			
		||||
@@ -51,15 +51,22 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                NadekoBot.Client.UserJoined += Client_UserJoined;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private static async Task Client_UserJoined(IGuildUser usr)
 | 
			
		||||
            private static async void Client_UserJoined(IGuildUser usr)
 | 
			
		||||
            {
 | 
			
		||||
                ConcurrentHashSet<ulong> muted;
 | 
			
		||||
                MutedUsers.TryGetValue(usr.Guild.Id, out muted);
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    ConcurrentHashSet<ulong> muted;
 | 
			
		||||
                    MutedUsers.TryGetValue(usr.Guild.Id, out muted);
 | 
			
		||||
 | 
			
		||||
                if (muted == null || !muted.Contains(usr.Id))
 | 
			
		||||
                    return;
 | 
			
		||||
                else
 | 
			
		||||
                    await Mute(usr).ConfigureAwait(false);
 | 
			
		||||
                    if (muted == null || !muted.Contains(usr.Id))
 | 
			
		||||
                        return;
 | 
			
		||||
                    else
 | 
			
		||||
                        await Mute(usr).ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex)
 | 
			
		||||
                {
 | 
			
		||||
                    _log.Warn(ex);
 | 
			
		||||
                }
 | 
			
		||||
                    
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
@@ -80,7 +87,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                    
 | 
			
		||||
                    await uow.CompleteAsync().ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                await UserMuted(usr, MuteType.All).ConfigureAwait(false);
 | 
			
		||||
                UserMuted(usr, MuteType.All);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public static async Task Unmute(IGuildUser usr)
 | 
			
		||||
@@ -99,7 +106,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                        muted.TryRemove(usr.Id);
 | 
			
		||||
                    await uow.CompleteAsync().ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                await UserUnmuted(usr, MuteType.All).ConfigureAwait(false);
 | 
			
		||||
                UserUnmuted(usr, MuteType.All);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public static async Task<IRole> GetMuteRole(IGuild guild)
 | 
			
		||||
@@ -211,7 +218,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    await user.AddRolesAsync(await GetMuteRole(channel.Guild).ConfigureAwait(false)).ConfigureAwait(false);
 | 
			
		||||
                    await UserMuted(user, MuteType.Chat).ConfigureAwait(false);
 | 
			
		||||
                    UserMuted(user, MuteType.Chat);
 | 
			
		||||
                    await channel.SendConfirmAsync($"✏️🚫 **{user}** has been **muted** from chatting.").ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch
 | 
			
		||||
@@ -230,7 +237,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    await user.RemoveRolesAsync(await GetMuteRole(channel.Guild).ConfigureAwait(false)).ConfigureAwait(false);
 | 
			
		||||
                    await UserUnmuted(user, MuteType.Chat).ConfigureAwait(false);
 | 
			
		||||
                    UserUnmuted(user, MuteType.Chat);
 | 
			
		||||
                    await channel.SendConfirmAsync($"✏️✅ **{user}** has been **unmuted** from chatting.").ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch
 | 
			
		||||
@@ -249,7 +256,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    await user.ModifyAsync(usr => usr.Mute = true).ConfigureAwait(false);
 | 
			
		||||
                    await UserMuted(user, MuteType.Voice).ConfigureAwait(false);
 | 
			
		||||
                    UserMuted(user, MuteType.Voice);
 | 
			
		||||
                    await channel.SendConfirmAsync($"🎙🚫 **{user}** has been **voice muted**.").ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch
 | 
			
		||||
@@ -267,7 +274,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    await user.ModifyAsync(usr => usr.Mute = false).ConfigureAwait(false);
 | 
			
		||||
                    await UserUnmuted(user, MuteType.Voice).ConfigureAwait(false);
 | 
			
		||||
                    UserUnmuted(user, MuteType.Voice);
 | 
			
		||||
                    await channel.SendConfirmAsync($"🎙✅ **{user}** has been **voice unmuted**.").ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
                catch
 | 
			
		||||
 
 | 
			
		||||
@@ -79,7 +79,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                        if (limiter.CheckUserRatelimit(usrMsg.Author.Id))
 | 
			
		||||
                            try { await usrMsg.DeleteAsync(); } catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
                    });
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                    return;
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -25,93 +25,85 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                NadekoBot.Client.UserLeft += UserLeft;
 | 
			
		||||
                _log = LogManager.GetCurrentClassLogger();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private static Task UserLeft(IGuildUser user)
 | 
			
		||||
            //todo optimize ASAP
 | 
			
		||||
            private static async void UserLeft(IGuildUser user)
 | 
			
		||||
            {
 | 
			
		||||
                var leftTask = Task.Run(async () =>
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    GuildConfig conf;
 | 
			
		||||
                    using (var uow = DbHandler.UnitOfWork())
 | 
			
		||||
                    {
 | 
			
		||||
                        conf = uow.GuildConfigs.For(user.Guild.Id, set => set);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    if (!conf.SendChannelByeMessage) return;
 | 
			
		||||
                    var channel = (await user.Guild.GetTextChannelsAsync()).SingleOrDefault(c => c.Id == conf.ByeMessageChannelId);
 | 
			
		||||
 | 
			
		||||
                    if (channel == null) //maybe warn the server owner that the channel is missing
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    var msg = conf.ChannelByeMessageText.Replace("%user%", user.Username).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
 | 
			
		||||
                    if (string.IsNullOrWhiteSpace(msg))
 | 
			
		||||
                        return;
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        GuildConfig conf;
 | 
			
		||||
                        using (var uow = DbHandler.UnitOfWork())
 | 
			
		||||
                        var toDelete = await channel.SendMessageAsync(msg.SanitizeMentions()).ConfigureAwait(false);
 | 
			
		||||
                        if (conf.AutoDeleteByeMessagesTimer > 0)
 | 
			
		||||
                        {
 | 
			
		||||
                            conf = uow.GuildConfigs.For(user.Guild.Id, set => set);
 | 
			
		||||
                            toDelete.DeleteAfter(conf.AutoDeleteByeMessagesTimer);
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (!conf.SendChannelByeMessage) return;
 | 
			
		||||
                        var channel = (await user.Guild.GetTextChannelsAsync()).SingleOrDefault(c => c.Id == conf.ByeMessageChannelId);
 | 
			
		||||
 | 
			
		||||
                        if (channel == null) //maybe warn the server owner that the channel is missing
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                        var msg = conf.ChannelByeMessageText.Replace("%user%", user.Username).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
 | 
			
		||||
                        if (string.IsNullOrWhiteSpace(msg))
 | 
			
		||||
                            return;
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            var toDelete = await channel.SendMessageAsync(msg.SanitizeMentions()).ConfigureAwait(false);
 | 
			
		||||
                            if (conf.AutoDeleteByeMessagesTimer > 0)
 | 
			
		||||
                            {
 | 
			
		||||
                                toDelete.DeleteAfter(conf.AutoDeleteByeMessagesTimer);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
                    }
 | 
			
		||||
                    catch { }
 | 
			
		||||
                });
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
                    catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
                }
 | 
			
		||||
                catch { }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private static Task UserJoined(IGuildUser user)
 | 
			
		||||
            private static async void UserJoined(IGuildUser user)
 | 
			
		||||
            {
 | 
			
		||||
                var joinedTask = Task.Run(async () =>
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    GuildConfig conf;
 | 
			
		||||
                    using (var uow = DbHandler.UnitOfWork())
 | 
			
		||||
                    {
 | 
			
		||||
                        GuildConfig conf;
 | 
			
		||||
                        using (var uow = DbHandler.UnitOfWork())
 | 
			
		||||
                        {
 | 
			
		||||
                            conf = uow.GuildConfigs.For(user.Guild.Id, set => set);
 | 
			
		||||
                        }
 | 
			
		||||
                        conf = uow.GuildConfigs.For(user.Guild.Id, set => set);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                        if (conf.SendChannelGreetMessage)
 | 
			
		||||
                    if (conf.SendChannelGreetMessage)
 | 
			
		||||
                    {
 | 
			
		||||
                        var channel = (await user.Guild.GetTextChannelsAsync()).SingleOrDefault(c => c.Id == conf.GreetMessageChannelId);
 | 
			
		||||
                        if (channel != null) //maybe warn the server owner that the channel is missing
 | 
			
		||||
                        {
 | 
			
		||||
                            var channel = (await user.Guild.GetTextChannelsAsync()).SingleOrDefault(c => c.Id == conf.GreetMessageChannelId);
 | 
			
		||||
                            if (channel != null) //maybe warn the server owner that the channel is missing
 | 
			
		||||
                            var msg = conf.ChannelGreetMessageText.Replace("%user%", user.Mention).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
 | 
			
		||||
                            if (!string.IsNullOrWhiteSpace(msg))
 | 
			
		||||
                            {
 | 
			
		||||
                                var msg = conf.ChannelGreetMessageText.Replace("%user%", user.Mention).Replace("%id%", user.Id.ToString()).Replace("%server%", user.Guild.Name);
 | 
			
		||||
                                if (!string.IsNullOrWhiteSpace(msg))
 | 
			
		||||
                                try
 | 
			
		||||
                                {
 | 
			
		||||
                                    try
 | 
			
		||||
                                    var toDelete = await channel.SendMessageAsync(msg.SanitizeMentions()).ConfigureAwait(false);
 | 
			
		||||
                                    if (conf.AutoDeleteGreetMessagesTimer > 0)
 | 
			
		||||
                                    {
 | 
			
		||||
                                        var toDelete = await channel.SendMessageAsync(msg.SanitizeMentions()).ConfigureAwait(false);
 | 
			
		||||
                                        if (conf.AutoDeleteGreetMessagesTimer > 0)
 | 
			
		||||
                                        {
 | 
			
		||||
                                            toDelete.DeleteAfter(conf.AutoDeleteGreetMessagesTimer);
 | 
			
		||||
                                        }
 | 
			
		||||
                                        toDelete.DeleteAfter(conf.AutoDeleteGreetMessagesTimer);
 | 
			
		||||
                                    }
 | 
			
		||||
                                    catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if (conf.SendDmGreetMessage)
 | 
			
		||||
                        {
 | 
			
		||||
                            var channel = await user.CreateDMChannelAsync();
 | 
			
		||||
 | 
			
		||||
                            if (channel != null)
 | 
			
		||||
                            {
 | 
			
		||||
                                var msg = conf.DmGreetMessageText.Replace("%user%", user.Username).Replace("%server%", user.Guild.Name);
 | 
			
		||||
                                if (!string.IsNullOrWhiteSpace(msg))
 | 
			
		||||
                                {
 | 
			
		||||
                                    await channel.SendConfirmAsync(msg).ConfigureAwait(false);
 | 
			
		||||
                                }
 | 
			
		||||
                                catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    catch { }
 | 
			
		||||
                });
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                    if (conf.SendDmGreetMessage)
 | 
			
		||||
                    {
 | 
			
		||||
                        var channel = await user.CreateDMChannelAsync();
 | 
			
		||||
 | 
			
		||||
                        if (channel != null)
 | 
			
		||||
                        {
 | 
			
		||||
                            var msg = conf.DmGreetMessageText.Replace("%user%", user.Username).Replace("%server%", user.Guild.Name);
 | 
			
		||||
                            if (!string.IsNullOrWhiteSpace(msg))
 | 
			
		||||
                            {
 | 
			
		||||
                                await channel.SendConfirmAsync(msg).ConfigureAwait(false);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                catch { }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
@@ -135,7 +127,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            {
 | 
			
		||||
                if (timer < 0 || timer > 600)
 | 
			
		||||
                    return;
 | 
			
		||||
                
 | 
			
		||||
 | 
			
		||||
                using (var uow = DbHandler.UnitOfWork())
 | 
			
		||||
                {
 | 
			
		||||
                    var conf = uow.GuildConfigs.For(id, set => set);
 | 
			
		||||
@@ -173,7 +165,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                }
 | 
			
		||||
                return enabled;
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            [RequirePermission(GuildPermission.ManageGuild)]
 | 
			
		||||
@@ -343,7 +335,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                if (!sendByeEnabled)
 | 
			
		||||
                    await channel.SendConfirmAsync($"ℹ️ Enable bye messsages by typing `{NadekoBot.ModulePrefixes[typeof(Administration).Name]}bye`").ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            public static bool SetByeMessage(ulong guildId, ref string message)
 | 
			
		||||
            {
 | 
			
		||||
                message = message?.SanitizeMentions();
 | 
			
		||||
@@ -394,4 +386,4 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
@@ -18,7 +18,7 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
        public class VoicePlusTextCommands
 | 
			
		||||
        {
 | 
			
		||||
            private static Regex channelNameRegex = new Regex(@"[^a-zA-Z0-9 -]", RegexOptions.Compiled);
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
            private static ConcurrentHashSet<ulong> voicePlusTextCache { get; }
 | 
			
		||||
            static VoicePlusTextCommands()
 | 
			
		||||
            {
 | 
			
		||||
@@ -29,76 +29,73 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
                NadekoBot.Client.UserVoiceStateUpdated += UserUpdatedEventHandler;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private static Task UserUpdatedEventHandler(IUser iuser, IVoiceState before, IVoiceState after)
 | 
			
		||||
            private static async void UserUpdatedEventHandler(IUser iuser, IVoiceState before, IVoiceState after)
 | 
			
		||||
            {
 | 
			
		||||
                var user = (iuser as IGuildUser);
 | 
			
		||||
                var guild = user?.Guild;
 | 
			
		||||
 | 
			
		||||
                if (guild == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                var task = Task.Run(async () =>
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    var botUserPerms = guild.GetCurrentUser().GuildPermissions;
 | 
			
		||||
 | 
			
		||||
                    if (before.VoiceChannel == after.VoiceChannel) return;
 | 
			
		||||
 | 
			
		||||
                    if (!voicePlusTextCache.Contains(guild.Id))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    if (!botUserPerms.ManageChannels || !botUserPerms.ManageRoles)
 | 
			
		||||
                    {
 | 
			
		||||
                        var botUserPerms = guild.GetCurrentUser().GuildPermissions;
 | 
			
		||||
                    
 | 
			
		||||
                        if (before.VoiceChannel == after.VoiceChannel) return;
 | 
			
		||||
                        
 | 
			
		||||
                        if (!voicePlusTextCache.Contains(guild.Id))
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                        if (!botUserPerms.ManageChannels || !botUserPerms.ManageRoles)
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            try
 | 
			
		||||
                            {
 | 
			
		||||
                                await (await guild.GetOwnerAsync()).SendErrorAsync(
 | 
			
		||||
                                    "⚠️ I don't have **manage server** and/or **manage channels** permission," +
 | 
			
		||||
                                    $" so I cannot run `voice+text` on **{guild.Name}** server.").ConfigureAwait(false);
 | 
			
		||||
                            }
 | 
			
		||||
                            catch { }
 | 
			
		||||
                            using (var uow = DbHandler.UnitOfWork())
 | 
			
		||||
                            {
 | 
			
		||||
                                uow.GuildConfigs.For(guild.Id, set => set).VoicePlusTextEnabled = false;
 | 
			
		||||
                                voicePlusTextCache.TryRemove(guild.Id);
 | 
			
		||||
                                await uow.CompleteAsync().ConfigureAwait(false);
 | 
			
		||||
                            }
 | 
			
		||||
                            return;
 | 
			
		||||
                            await (await guild.GetOwnerAsync()).SendErrorAsync(
 | 
			
		||||
                                "⚠️ I don't have **manage server** and/or **manage channels** permission," +
 | 
			
		||||
                                $" so I cannot run `voice+text` on **{guild.Name}** server.").ConfigureAwait(false);
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                        var beforeVch = before.VoiceChannel;
 | 
			
		||||
                        if (beforeVch != null)
 | 
			
		||||
                        catch { }
 | 
			
		||||
                        using (var uow = DbHandler.UnitOfWork())
 | 
			
		||||
                        {
 | 
			
		||||
                            var textChannel = guild.GetTextChannels().Where(t => t.Name == GetChannelName(beforeVch.Name).ToLowerInvariant()).FirstOrDefault();
 | 
			
		||||
                            if (textChannel != null)
 | 
			
		||||
                                await textChannel.AddPermissionOverwriteAsync(user,
 | 
			
		||||
                                    new OverwritePermissions(readMessages: PermValue.Deny,
 | 
			
		||||
                                                       sendMessages: PermValue.Deny)).ConfigureAwait(false);
 | 
			
		||||
                            uow.GuildConfigs.For(guild.Id, set => set).VoicePlusTextEnabled = false;
 | 
			
		||||
                            voicePlusTextCache.TryRemove(guild.Id);
 | 
			
		||||
                            await uow.CompleteAsync().ConfigureAwait(false);
 | 
			
		||||
                        }
 | 
			
		||||
                        var afterVch = after.VoiceChannel;
 | 
			
		||||
                        if (afterVch != null && guild.AFKChannelId != afterVch.Id)
 | 
			
		||||
                        {
 | 
			
		||||
                            var textChannel = guild.GetTextChannels()
 | 
			
		||||
                                                        .Where(t => t.Name ==  GetChannelName(afterVch.Name).ToLowerInvariant())
 | 
			
		||||
                                                        .FirstOrDefault();
 | 
			
		||||
                            if (textChannel == null)
 | 
			
		||||
                            {
 | 
			
		||||
                                textChannel = (await guild.CreateTextChannelAsync(GetChannelName(afterVch.Name).ToLowerInvariant()).ConfigureAwait(false));
 | 
			
		||||
                                await textChannel.AddPermissionOverwriteAsync(guild.EveryoneRole,
 | 
			
		||||
                                    new OverwritePermissions(readMessages: PermValue.Deny,
 | 
			
		||||
                                                       sendMessages: PermValue.Deny)).ConfigureAwait(false);
 | 
			
		||||
                            }
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                    var beforeVch = before.VoiceChannel;
 | 
			
		||||
                    if (beforeVch != null)
 | 
			
		||||
                    {
 | 
			
		||||
                        var textChannel = guild.GetTextChannels().Where(t => t.Name == GetChannelName(beforeVch.Name).ToLowerInvariant()).FirstOrDefault();
 | 
			
		||||
                        if (textChannel != null)
 | 
			
		||||
                            await textChannel.AddPermissionOverwriteAsync(user,
 | 
			
		||||
                                new OverwritePermissions(readMessages: PermValue.Allow,
 | 
			
		||||
                                                        sendMessages: PermValue.Allow)).ConfigureAwait(false);
 | 
			
		||||
                        }
 | 
			
		||||
                                new OverwritePermissions(readMessages: PermValue.Deny,
 | 
			
		||||
                                                   sendMessages: PermValue.Deny)).ConfigureAwait(false);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (Exception ex)
 | 
			
		||||
                    var afterVch = after.VoiceChannel;
 | 
			
		||||
                    if (afterVch != null && guild.AFKChannelId != afterVch.Id)
 | 
			
		||||
                    {
 | 
			
		||||
                        Console.WriteLine(ex);
 | 
			
		||||
                        var textChannel = guild.GetTextChannels()
 | 
			
		||||
                                                    .Where(t => t.Name == GetChannelName(afterVch.Name).ToLowerInvariant())
 | 
			
		||||
                                                    .FirstOrDefault();
 | 
			
		||||
                        if (textChannel == null)
 | 
			
		||||
                        {
 | 
			
		||||
                            textChannel = (await guild.CreateTextChannelAsync(GetChannelName(afterVch.Name).ToLowerInvariant()).ConfigureAwait(false));
 | 
			
		||||
                            await textChannel.AddPermissionOverwriteAsync(guild.EveryoneRole,
 | 
			
		||||
                                new OverwritePermissions(readMessages: PermValue.Deny,
 | 
			
		||||
                                                   sendMessages: PermValue.Deny)).ConfigureAwait(false);
 | 
			
		||||
                        }
 | 
			
		||||
                        await textChannel.AddPermissionOverwriteAsync(user,
 | 
			
		||||
                            new OverwritePermissions(readMessages: PermValue.Allow,
 | 
			
		||||
                                                    sendMessages: PermValue.Allow)).ConfigureAwait(false);
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex)
 | 
			
		||||
                {
 | 
			
		||||
                    Console.WriteLine(ex);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private static string GetChannelName(string voiceName) =>
 | 
			
		||||
@@ -187,4 +184,4 @@ namespace NadekoBot.Modules.Administration
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
@@ -209,15 +209,15 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                private Task Client_MessageReceived(IMessage imsg)
 | 
			
		||||
                private void Client_MessageReceived(IMessage imsg)
 | 
			
		||||
                {
 | 
			
		||||
                    var msg = imsg as IUserMessage;
 | 
			
		||||
                    if (msg == null)
 | 
			
		||||
                        return Task.CompletedTask;
 | 
			
		||||
                        return;
 | 
			
		||||
                    if (msg.IsAuthor() || !(imsg.Channel is ITextChannel) || imsg.Channel != raceChannel)
 | 
			
		||||
                        return Task.CompletedTask;
 | 
			
		||||
                        return;
 | 
			
		||||
                    messagesSinceGameStarted++;
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                private async Task CheckForFullGameAsync(CancellationToken cancelToken)
 | 
			
		||||
@@ -277,10 +277,7 @@ namespace NadekoBot.Modules.Gambling
 | 
			
		||||
                    this.AmountBet = amount;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                public override int GetHashCode()
 | 
			
		||||
                {
 | 
			
		||||
                    return User.GetHashCode();
 | 
			
		||||
                }
 | 
			
		||||
                public override int GetHashCode() => User.GetHashCode();
 | 
			
		||||
 | 
			
		||||
                public override bool Equals(object obj)
 | 
			
		||||
                {
 | 
			
		||||
 
 | 
			
		||||
@@ -163,101 +163,97 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
                await End().ConfigureAwait(false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private Task PotentialAcro(IMessage arg)
 | 
			
		||||
            private async void PotentialAcro(IMessage arg)
 | 
			
		||||
            {
 | 
			
		||||
                var t = Task.Run(async () =>
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    var msg = arg as IUserMessage;
 | 
			
		||||
                    if (msg == null || msg.Author.IsBot || msg.Channel.Id != channel.Id)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    ++spamCount;
 | 
			
		||||
 | 
			
		||||
                    var guildUser = (IGuildUser)msg.Author;
 | 
			
		||||
 | 
			
		||||
                    var input = msg.Content.ToUpperInvariant().Trim();
 | 
			
		||||
 | 
			
		||||
                    if (phase == AcroPhase.Submitting)
 | 
			
		||||
                    {
 | 
			
		||||
                        var msg = arg as IUserMessage;
 | 
			
		||||
                        if (msg == null || msg.Author.IsBot || msg.Channel.Id != channel.Id)
 | 
			
		||||
                        if (spamCount > 10)
 | 
			
		||||
                        {
 | 
			
		||||
                            spamCount = 0;
 | 
			
		||||
                            try { await channel.EmbedAsync(GetEmbed().Build()).ConfigureAwait(false); }
 | 
			
		||||
                            catch { }
 | 
			
		||||
                        }
 | 
			
		||||
                        //user didn't input something already
 | 
			
		||||
                        IGuildUser throwaway;
 | 
			
		||||
                        if (submissions.TryGetValue(input, out throwaway))
 | 
			
		||||
                            return;
 | 
			
		||||
                        var inputWords = input.Split(' '); //get all words
 | 
			
		||||
 | 
			
		||||
                        if (inputWords.Length != startingLetters.Length) // number of words must be the same as the number of the starting letters
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                        ++spamCount;
 | 
			
		||||
 | 
			
		||||
                        var guildUser = (IGuildUser)msg.Author;
 | 
			
		||||
                        
 | 
			
		||||
                        var input = msg.Content.ToUpperInvariant().Trim();
 | 
			
		||||
 | 
			
		||||
                        if (phase == AcroPhase.Submitting)
 | 
			
		||||
                        for (int i = 0; i < startingLetters.Length; i++)
 | 
			
		||||
                        {
 | 
			
		||||
                            if (spamCount > 10)
 | 
			
		||||
                            {
 | 
			
		||||
                                spamCount = 0;
 | 
			
		||||
                                try { await channel.EmbedAsync(GetEmbed().Build()).ConfigureAwait(false); }
 | 
			
		||||
                                catch { }
 | 
			
		||||
                            }
 | 
			
		||||
                            //user didn't input something already
 | 
			
		||||
                            IGuildUser throwaway;
 | 
			
		||||
                            if (submissions.TryGetValue(input, out throwaway))
 | 
			
		||||
                            var letter = startingLetters[i];
 | 
			
		||||
 | 
			
		||||
                            if (!inputWords[i].StartsWith(letter.ToString())) // all first letters must match
 | 
			
		||||
                                return;
 | 
			
		||||
                            var inputWords = input.Split(' '); //get all words
 | 
			
		||||
 | 
			
		||||
                            if (inputWords.Length != startingLetters.Length) // number of words must be the same as the number of the starting letters
 | 
			
		||||
                                return;
 | 
			
		||||
 | 
			
		||||
                            for (int i = 0; i < startingLetters.Length; i++)
 | 
			
		||||
                            {
 | 
			
		||||
                                var letter = startingLetters[i];
 | 
			
		||||
 | 
			
		||||
                                if (!inputWords[i].StartsWith(letter.ToString())) // all first letters must match
 | 
			
		||||
                                    return;
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            //try adding it to the list of answers
 | 
			
		||||
                            if (!submissions.TryAdd(input, guildUser))
 | 
			
		||||
                                return;
 | 
			
		||||
 | 
			
		||||
                            // all good. valid input. answer recorded
 | 
			
		||||
                            await channel.SendConfirmAsync("Acrophobia", $"{guildUser.Mention} submitted their sentence. ({submissions.Count} total)");
 | 
			
		||||
                            try
 | 
			
		||||
                            {
 | 
			
		||||
                                await msg.DeleteAsync();
 | 
			
		||||
                            }
 | 
			
		||||
                            catch
 | 
			
		||||
                            {
 | 
			
		||||
                                await msg.DeleteAsync(); //try twice
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        else if (phase == AcroPhase.Voting)
 | 
			
		||||
 | 
			
		||||
                        //try adding it to the list of answers
 | 
			
		||||
                        if (!submissions.TryAdd(input, guildUser))
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                        // all good. valid input. answer recorded
 | 
			
		||||
                        await channel.SendConfirmAsync("Acrophobia", $"{guildUser.Mention} submitted their sentence. ({submissions.Count} total)");
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            if (spamCount > 10)
 | 
			
		||||
                            {
 | 
			
		||||
                                spamCount = 0;
 | 
			
		||||
                                try { await channel.EmbedAsync(GetEmbed().Build()).ConfigureAwait(false); }
 | 
			
		||||
                                catch { }
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            IGuildUser usr;
 | 
			
		||||
                            //if (submissions.TryGetValue(input, out usr) && usr.Id != guildUser.Id)
 | 
			
		||||
                            //{
 | 
			
		||||
                            //    if (!usersWhoVoted.Add(guildUser.Id))
 | 
			
		||||
                            //        return;
 | 
			
		||||
                            //    votes.AddOrUpdate(input, 1, (key, old) => ++old);
 | 
			
		||||
                            //    await channel.SendConfirmAsync("Acrophobia", $"{guildUser.Mention} cast their vote!").ConfigureAwait(false);
 | 
			
		||||
                            //    await msg.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
                            //    return;
 | 
			
		||||
                            //}
 | 
			
		||||
 | 
			
		||||
                            int num;
 | 
			
		||||
                            if (int.TryParse(input, out num) && num > 0 && num <= submissions.Count)
 | 
			
		||||
                            {
 | 
			
		||||
                                var kvp = submissions.Skip(num - 1).First();
 | 
			
		||||
                                usr = kvp.Value;
 | 
			
		||||
                                //can't vote for yourself, can't vote multiple times
 | 
			
		||||
                                if (usr.Id == guildUser.Id || !usersWhoVoted.Add(guildUser.Id))
 | 
			
		||||
                                    return;
 | 
			
		||||
                                votes.AddOrUpdate(kvp.Key, 1, (key, old) => ++old);
 | 
			
		||||
                                await channel.SendConfirmAsync("Acrophobia", $"{guildUser.Mention} cast their vote!").ConfigureAwait(false);
 | 
			
		||||
                                await msg.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
                                return;
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            await msg.DeleteAsync();
 | 
			
		||||
                        }
 | 
			
		||||
                        catch
 | 
			
		||||
                        {
 | 
			
		||||
                            await msg.DeleteAsync(); //try twice
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    catch { }
 | 
			
		||||
                });
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
                    else if (phase == AcroPhase.Voting)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (spamCount > 10)
 | 
			
		||||
                        {
 | 
			
		||||
                            spamCount = 0;
 | 
			
		||||
                            try { await channel.EmbedAsync(GetEmbed().Build()).ConfigureAwait(false); }
 | 
			
		||||
                            catch { }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        IGuildUser usr;
 | 
			
		||||
                        //if (submissions.TryGetValue(input, out usr) && usr.Id != guildUser.Id)
 | 
			
		||||
                        //{
 | 
			
		||||
                        //    if (!usersWhoVoted.Add(guildUser.Id))
 | 
			
		||||
                        //        return;
 | 
			
		||||
                        //    votes.AddOrUpdate(input, 1, (key, old) => ++old);
 | 
			
		||||
                        //    await channel.SendConfirmAsync("Acrophobia", $"{guildUser.Mention} cast their vote!").ConfigureAwait(false);
 | 
			
		||||
                        //    await msg.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
                        //    return;
 | 
			
		||||
                        //}
 | 
			
		||||
 | 
			
		||||
                        int num;
 | 
			
		||||
                        if (int.TryParse(input, out num) && num > 0 && num <= submissions.Count)
 | 
			
		||||
                        {
 | 
			
		||||
                            var kvp = submissions.Skip(num - 1).First();
 | 
			
		||||
                            usr = kvp.Value;
 | 
			
		||||
                            //can't vote for yourself, can't vote multiple times
 | 
			
		||||
                            if (usr.Id == guildUser.Id || !usersWhoVoted.Add(guildUser.Id))
 | 
			
		||||
                                return;
 | 
			
		||||
                            votes.AddOrUpdate(kvp.Key, 1, (key, old) => ++old);
 | 
			
		||||
                            await channel.SendConfirmAsync("Acrophobia", $"{guildUser.Mention} cast their vote!").ConfigureAwait(false);
 | 
			
		||||
                            await msg.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                catch { }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            public async Task End()
 | 
			
		||||
 
 | 
			
		||||
@@ -124,94 +124,84 @@ namespace NadekoBot.Modules.Games.Commands.Hangman
 | 
			
		||||
                await GameChannel.EmbedAsync(embed.WithOkColor().Build()).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Task PotentialGuess(IMessage msg)
 | 
			
		||||
        private async void PotentialGuess(IMessage msg)
 | 
			
		||||
        {
 | 
			
		||||
            if (msg.Channel != GameChannel)
 | 
			
		||||
                return Task.CompletedTask; // message's channel has to be the same as game's
 | 
			
		||||
                return; // message's channel has to be the same as game's
 | 
			
		||||
            if (msg.Content.Length != 1) // message must be 1 char long
 | 
			
		||||
            {
 | 
			
		||||
                if (++MessagesSinceLastPost > 10)
 | 
			
		||||
                {
 | 
			
		||||
                    MessagesSinceLastPost = 0;
 | 
			
		||||
                    Task.Run(async () =>
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            await GameChannel.SendConfirmAsync("Hangman Game",
 | 
			
		||||
                                ScrambledWord + "\n" + GetHangman(),
 | 
			
		||||
                                footer: string.Join(" ", Guesses)).ConfigureAwait(false);
 | 
			
		||||
                        }
 | 
			
		||||
                        catch { }
 | 
			
		||||
                    });
 | 
			
		||||
                        await GameChannel.SendConfirmAsync("Hangman Game",
 | 
			
		||||
                            ScrambledWord + "\n" + GetHangman(),
 | 
			
		||||
                            footer: string.Join(" ", Guesses)).ConfigureAwait(false);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch { }
 | 
			
		||||
                }
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (!(char.IsLetter(msg.Content[0]) || char.IsDigit(msg.Content[0])))// and a letter or a digit
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            var guess = char.ToUpperInvariant(msg.Content[0]);
 | 
			
		||||
 | 
			
		||||
            Task.Run(async () =>
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                if (Guesses.Contains(guess))
 | 
			
		||||
                {
 | 
			
		||||
                    if (Guesses.Contains(guess))
 | 
			
		||||
                    MessagesSinceLastPost = 0;
 | 
			
		||||
                    ++Errors;
 | 
			
		||||
                    if (Errors < MaxErrors)
 | 
			
		||||
                        await GameChannel.SendErrorAsync("Hangman Game", $"{msg.Author.Mention} Letter `{guess}` has already been used.\n" + ScrambledWord + "\n" + GetHangman(),
 | 
			
		||||
                            footer: string.Join(" ", Guesses)).ConfigureAwait(false);
 | 
			
		||||
                    else
 | 
			
		||||
                        await End().ConfigureAwait(false);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                Guesses.Add(guess);
 | 
			
		||||
 | 
			
		||||
                if (Term.Word.ToUpperInvariant().Contains(guess))
 | 
			
		||||
                {
 | 
			
		||||
                    if (GuessedAll)
 | 
			
		||||
                    {
 | 
			
		||||
                        MessagesSinceLastPost = 0;
 | 
			
		||||
                        ++Errors;
 | 
			
		||||
                        if (Errors < MaxErrors)
 | 
			
		||||
                            await GameChannel.SendErrorAsync("Hangman Game", $"{msg.Author.Mention} Letter `{guess}` has already been used.\n" + ScrambledWord + "\n" + GetHangman(),
 | 
			
		||||
                                footer: string.Join(" ", Guesses)).ConfigureAwait(false);
 | 
			
		||||
                        else
 | 
			
		||||
                            await End().ConfigureAwait(false);
 | 
			
		||||
                        try { await GameChannel.SendConfirmAsync("Hangman Game", $"{msg.Author.Mention} guessed a letter `{guess}`!").ConfigureAwait(false); } catch { }
 | 
			
		||||
 | 
			
		||||
                        await End().ConfigureAwait(false);
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    Guesses.Add(guess);
 | 
			
		||||
 | 
			
		||||
                    if (Term.Word.ToUpperInvariant().Contains(guess))
 | 
			
		||||
                    MessagesSinceLastPost = 0;
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        if (GuessedAll)
 | 
			
		||||
                        {
 | 
			
		||||
                            try { await GameChannel.SendConfirmAsync("Hangman Game", $"{msg.Author.Mention} guessed a letter `{guess}`!").ConfigureAwait(false); } catch { }
 | 
			
		||||
 | 
			
		||||
                          await End().ConfigureAwait(false);
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
                        MessagesSinceLastPost = 0;
 | 
			
		||||
                        try { await GameChannel.SendConfirmAsync("Hangman Game", $"{msg.Author.Mention} guessed a letter `{guess}`!\n" + ScrambledWord + "\n" + GetHangman(),
 | 
			
		||||
                            footer: string.Join(" ", Guesses)).ConfigureAwait(false); } catch { }
 | 
			
		||||
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        MessagesSinceLastPost = 0;
 | 
			
		||||
                        ++Errors;
 | 
			
		||||
                        if (Errors < MaxErrors)
 | 
			
		||||
                            await GameChannel.SendErrorAsync("Hangman Game", $"{msg.Author.Mention} Letter `{guess}` does not exist.\n" + ScrambledWord + "\n" + GetHangman(),
 | 
			
		||||
                                footer: string.Join(" ", Guesses)).ConfigureAwait(false);
 | 
			
		||||
                        else
 | 
			
		||||
                            await End().ConfigureAwait(false);
 | 
			
		||||
                        await GameChannel.SendConfirmAsync("Hangman Game", $"{msg.Author.Mention} guessed a letter `{guess}`!\n" + ScrambledWord + "\n" + GetHangman(),
 | 
			
		||||
                      footer: string.Join(" ", Guesses)).ConfigureAwait(false);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch { }
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
                catch { }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    MessagesSinceLastPost = 0;
 | 
			
		||||
                    ++Errors;
 | 
			
		||||
                    if (Errors < MaxErrors)
 | 
			
		||||
                        await GameChannel.SendErrorAsync("Hangman Game", $"{msg.Author.Mention} Letter `{guess}` does not exist.\n" + ScrambledWord + "\n" + GetHangman(),
 | 
			
		||||
                            footer: string.Join(" ", Guesses)).ConfigureAwait(false);
 | 
			
		||||
                    else
 | 
			
		||||
                        await End().ConfigureAwait(false);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
            });
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
            }
 | 
			
		||||
            catch { }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string GetHangman()
 | 
			
		||||
        {
 | 
			
		||||
            return
 | 
			
		||||
$@"\_\_\_\_\_\_\_\_\_
 | 
			
		||||
        public string GetHangman() => $@"\_\_\_\_\_\_\_\_\_
 | 
			
		||||
      |           |
 | 
			
		||||
      |           |
 | 
			
		||||
   {(Errors > 0 ? "😲" : "      ")}        |
 | 
			
		||||
   {(Errors > 1 ? "/" : "  ")} {(Errors > 2 ? "|" : "  ")} {(Errors > 3 ? "\\" : "  ")}       | 
 | 
			
		||||
    {(Errors > 4 ? "/" : "  ")} {(Errors > 5 ? "\\" : "  ")}        |
 | 
			
		||||
               /-\";
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -57,46 +57,43 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private static Task PotentialFlowerGeneration(IMessage imsg)
 | 
			
		||||
            private static async void PotentialFlowerGeneration(IMessage imsg)
 | 
			
		||||
            {
 | 
			
		||||
                var msg = imsg as IUserMessage;
 | 
			
		||||
                if (msg == null || msg.IsAuthor() || msg.Author.IsBot)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                var channel = imsg.Channel as ITextChannel;
 | 
			
		||||
                if (channel == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                if (!generationChannels.Contains(channel.Id))
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                var t = Task.Run(async () =>
 | 
			
		||||
                var lastGeneration = lastGenerations.GetOrAdd(channel.Id, DateTime.MinValue);
 | 
			
		||||
                var rng = new NadekoRandom();
 | 
			
		||||
 | 
			
		||||
                if (DateTime.Now - TimeSpan.FromSeconds(cooldown) < lastGeneration) //recently generated in this channel, don't generate again
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                var num = rng.Next(1, 101) + chance * 100;
 | 
			
		||||
 | 
			
		||||
                if (num > 100)
 | 
			
		||||
                {
 | 
			
		||||
                    var lastGeneration = lastGenerations.GetOrAdd(channel.Id, DateTime.MinValue);
 | 
			
		||||
                    var rng = new NadekoRandom();
 | 
			
		||||
 | 
			
		||||
                    if (DateTime.Now - TimeSpan.FromSeconds(cooldown) < lastGeneration) //recently generated in this channel, don't generate again
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    var num = rng.Next(1, 101) + chance * 100;
 | 
			
		||||
 | 
			
		||||
                    if (num > 100)
 | 
			
		||||
                    lastGenerations.AddOrUpdate(channel.Id, DateTime.Now, (id, old) => DateTime.Now);
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        lastGenerations.AddOrUpdate(channel.Id, DateTime.Now, (id, old) => DateTime.Now);
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            var sent = await channel.SendFileAsync(
 | 
			
		||||
                                GetRandomCurrencyImagePath(), 
 | 
			
		||||
                                $"❗ A random { Gambling.Gambling.CurrencyName } appeared! Pick it up by typing `{NadekoBot.ModulePrefixes[typeof(Games).Name]}pick`")
 | 
			
		||||
                                    .ConfigureAwait(false);
 | 
			
		||||
                            plantedFlowers.AddOrUpdate(channel.Id, new List<IUserMessage>() { sent }, (id, old) => { old.Add(sent); return old; });
 | 
			
		||||
                        }
 | 
			
		||||
                        catch { }
 | 
			
		||||
                        
 | 
			
		||||
                        var sent = await channel.SendFileAsync(
 | 
			
		||||
                            GetRandomCurrencyImagePath(),
 | 
			
		||||
                            $"❗ A random { Gambling.Gambling.CurrencyName } appeared! Pick it up by typing `{NadekoBot.ModulePrefixes[typeof(Games).Name]}pick`")
 | 
			
		||||
                                .ConfigureAwait(false);
 | 
			
		||||
                        plantedFlowers.AddOrUpdate(channel.Id, new List<IUserMessage>() { sent }, (id, old) => { old.Add(sent); return old; });
 | 
			
		||||
                    }
 | 
			
		||||
                });
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
                    catch { }
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
            [RequireContext(ContextType.Guild)]
 | 
			
		||||
            public async Task Pick(IUserMessage imsg)
 | 
			
		||||
 
 | 
			
		||||
@@ -124,61 +124,56 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Task Vote(IMessage imsg)
 | 
			
		||||
        private async void Vote(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            // has to be a user message
 | 
			
		||||
            var msg = imsg as IUserMessage;
 | 
			
		||||
            if (msg == null || msg.Author.IsBot)
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            // has to be an integer
 | 
			
		||||
            int vote;
 | 
			
		||||
            if (!int.TryParse(imsg.Content, out vote))
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
                return;
 | 
			
		||||
            if (vote < 1 || vote > answers.Length)
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
            var t = Task.Run(async () =>
 | 
			
		||||
                return;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                IMessageChannel ch;
 | 
			
		||||
                if (isPublic)
 | 
			
		||||
                {
 | 
			
		||||
                    IMessageChannel ch;
 | 
			
		||||
                    if (isPublic)
 | 
			
		||||
                    //if public, channel must be the same the poll started in
 | 
			
		||||
                    if (originalMessage.Channel.Id != imsg.Channel.Id)
 | 
			
		||||
                        return;
 | 
			
		||||
                    ch = imsg.Channel;
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    //if private, channel must be dm channel
 | 
			
		||||
                    if ((ch = msg.Channel as IDMChannel) == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    // user must be a member of the guild this poll is in
 | 
			
		||||
                    var guildUsers = await guild.GetUsersAsync().ConfigureAwait(false);
 | 
			
		||||
                    if (!guildUsers.Any(u => u.Id == imsg.Author.Id))
 | 
			
		||||
                        return;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                //user can vote only once
 | 
			
		||||
                if (participants.TryAdd(msg.Author.Id, vote))
 | 
			
		||||
                {
 | 
			
		||||
                    if (!isPublic)
 | 
			
		||||
                    {
 | 
			
		||||
                        //if public, channel must be the same the poll started in
 | 
			
		||||
                        if (originalMessage.Channel.Id != imsg.Channel.Id)
 | 
			
		||||
                            return;
 | 
			
		||||
                        ch = imsg.Channel;
 | 
			
		||||
                        await ch.SendConfirmAsync($"Thanks for voting **{msg.Author.Username}**.").ConfigureAwait(false);
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        //if private, channel must be dm channel
 | 
			
		||||
                        if ((ch = msg.Channel as IDMChannel) == null)
 | 
			
		||||
                            return;
 | 
			
		||||
 | 
			
		||||
                        // user must be a member of the guild this poll is in
 | 
			
		||||
                        var guildUsers = await guild.GetUsersAsync().ConfigureAwait(false);
 | 
			
		||||
                        if (!guildUsers.Any(u => u.Id == imsg.Author.Id))
 | 
			
		||||
                            return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    //user can vote only once
 | 
			
		||||
                    if (participants.TryAdd(msg.Author.Id, vote))
 | 
			
		||||
                    {
 | 
			
		||||
                        if (!isPublic)
 | 
			
		||||
                        {
 | 
			
		||||
                            await ch.SendConfirmAsync($"Thanks for voting **{msg.Author.Username}**.").ConfigureAwait(false);
 | 
			
		||||
                        }
 | 
			
		||||
                        else
 | 
			
		||||
                        {
 | 
			
		||||
                            var toDelete = await ch.SendConfirmAsync($"{msg.Author.Mention} cast their vote.").ConfigureAwait(false);
 | 
			
		||||
                            toDelete.DeleteAfter(5);
 | 
			
		||||
                        }
 | 
			
		||||
                        var toDelete = await ch.SendConfirmAsync($"{msg.Author.Mention} cast their vote.").ConfigureAwait(false);
 | 
			
		||||
                        toDelete.DeleteAfter(5);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                catch { }
 | 
			
		||||
            });
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
            }
 | 
			
		||||
            catch { }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -105,42 +105,38 @@ namespace NadekoBot.Modules.Games
 | 
			
		||||
                NadekoBot.Client.MessageReceived += AnswerReceived;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private Task AnswerReceived(IMessage imsg)
 | 
			
		||||
            private async void AnswerReceived(IMessage imsg)
 | 
			
		||||
            {
 | 
			
		||||
                if (imsg.Author.IsBot)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                    return;
 | 
			
		||||
                var msg = imsg as IUserMessage;
 | 
			
		||||
                if (msg == null)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                var t = Task.Run(async () =>
 | 
			
		||||
                    return;
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    try
 | 
			
		||||
                    if (this.Channel == null || this.Channel.Id != this.Channel.Id) return;
 | 
			
		||||
 | 
			
		||||
                    var guess = msg.Content;
 | 
			
		||||
 | 
			
		||||
                    var distance = CurrentSentence.LevenshteinDistance(guess);
 | 
			
		||||
                    var decision = Judge(distance, guess.Length);
 | 
			
		||||
                    if (decision && !finishedUserIds.Contains(msg.Author.Id))
 | 
			
		||||
                    {
 | 
			
		||||
                        if (this.Channel == null || this.Channel.Id != this.Channel.Id) return;
 | 
			
		||||
 | 
			
		||||
                        var guess = msg.Content;
 | 
			
		||||
 | 
			
		||||
                        var distance = CurrentSentence.LevenshteinDistance(guess);
 | 
			
		||||
                        var decision = Judge(distance, guess.Length);
 | 
			
		||||
                        if (decision && !finishedUserIds.Contains(msg.Author.Id))
 | 
			
		||||
                        var wpm = CurrentSentence.Length / WORD_VALUE / sw.Elapsed.Seconds * 60;
 | 
			
		||||
                        finishedUserIds.Add(msg.Author.Id);
 | 
			
		||||
                        await Extensions.Extensions.EmbedAsync(this.Channel, (Discord.API.Embed)new EmbedBuilder().WithColor((uint)NadekoBot.OkColor)
 | 
			
		||||
                            .WithTitle((string)$"{msg.Author} finished the race!")
 | 
			
		||||
                            .AddField(efb => efb.WithName("Place").WithValue($"#{finishedUserIds.Count}").WithIsInline(true))
 | 
			
		||||
                            .AddField(efb => efb.WithName("WPM").WithValue($"{wpm:F2} *[{sw.Elapsed.Seconds.ToString()}sec]*").WithIsInline(true))
 | 
			
		||||
                            .AddField(efb => efb.WithName((string)"Errors").WithValue((string)distance.ToString()).WithIsInline((bool)true))
 | 
			
		||||
                            .Build()).ConfigureAwait(false);
 | 
			
		||||
                        if (finishedUserIds.Count % 4 == 0)
 | 
			
		||||
                        {
 | 
			
		||||
                            var wpm = CurrentSentence.Length / WORD_VALUE / sw.Elapsed.Seconds * 60;
 | 
			
		||||
                            finishedUserIds.Add(msg.Author.Id);
 | 
			
		||||
                            await Extensions.Extensions.EmbedAsync(this.Channel, (Discord.API.Embed)new EmbedBuilder().WithColor((uint)NadekoBot.OkColor)
 | 
			
		||||
                                .WithTitle((string)$"{msg.Author} finished the race!")
 | 
			
		||||
                                .AddField(efb => efb.WithName("Place").WithValue($"#{finishedUserIds.Count}").WithIsInline(true))
 | 
			
		||||
                                .AddField(efb => efb.WithName("WPM").WithValue($"{wpm:F2} *[{sw.Elapsed.Seconds.ToString()}sec]*").WithIsInline(true))
 | 
			
		||||
                                .AddField(efb => efb.WithName((string)"Errors").WithValue((string)distance.ToString()).WithIsInline((bool)true))
 | 
			
		||||
                                .Build()).ConfigureAwait(false);
 | 
			
		||||
                            if (finishedUserIds.Count % 4 == 0)
 | 
			
		||||
                            {
 | 
			
		||||
                                await Extensions.Extensions.SendConfirmAsync(this.Channel, (string)$":exclamation: A lot of people finished, here is the text for those still typing:\n\n**{Format.Sanitize((string)CurrentSentence.Replace((string)" ", (string)" \x200B")).SanitizeMentions()}**").ConfigureAwait(false);
 | 
			
		||||
                            }
 | 
			
		||||
                            await Extensions.Extensions.SendConfirmAsync(this.Channel, (string)$":exclamation: A lot of people finished, here is the text for those still typing:\n\n**{Format.Sanitize((string)CurrentSentence.Replace((string)" ", (string)" \x200B")).SanitizeMentions()}**").ConfigureAwait(false);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    catch { }
 | 
			
		||||
                });
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            private bool Judge(int errors, int textLength) => errors <= textLength / 25;
 | 
			
		||||
 
 | 
			
		||||
@@ -142,49 +142,47 @@ namespace NadekoBot.Modules.Games.Trivia
 | 
			
		||||
                try { await channel.SendConfirmAsync("Trivia Game", "Stopping after this question.").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Task PotentialGuess(IMessage imsg)
 | 
			
		||||
        private async void PotentialGuess(IMessage imsg)
 | 
			
		||||
        {
 | 
			
		||||
            if (imsg.Author.IsBot)
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            var umsg = imsg as IUserMessage;
 | 
			
		||||
            if (umsg == null)
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            var t = Task.Run(async () =>
 | 
			
		||||
                return;
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                var textChannel = umsg.Channel as ITextChannel;
 | 
			
		||||
                if (textChannel == null || textChannel.Guild != guild)
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                var guildUser = (IGuildUser)umsg.Author;
 | 
			
		||||
 | 
			
		||||
                var guess = false;
 | 
			
		||||
                await _guessLock.WaitAsync().ConfigureAwait(false);
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    var textChannel = umsg.Channel as ITextChannel;
 | 
			
		||||
                    if (textChannel == null || textChannel.Guild != guild)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    var guildUser = (IGuildUser)umsg.Author;
 | 
			
		||||
 | 
			
		||||
                    var guess = false;
 | 
			
		||||
                    await _guessLock.WaitAsync().ConfigureAwait(false);
 | 
			
		||||
                    try
 | 
			
		||||
                    if (GameActive && CurrentQuestion.IsAnswerCorrect(umsg.Content) && !triviaCancelSource.IsCancellationRequested)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (GameActive && CurrentQuestion.IsAnswerCorrect(umsg.Content) && !triviaCancelSource.IsCancellationRequested)
 | 
			
		||||
                        {
 | 
			
		||||
                            Users.AddOrUpdate(guildUser, 1, (gu, old) => ++old);
 | 
			
		||||
                            guess = true;
 | 
			
		||||
                        }
 | 
			
		||||
                        Users.AddOrUpdate(guildUser, 1, (gu, old) => ++old);
 | 
			
		||||
                        guess = true;
 | 
			
		||||
                    }
 | 
			
		||||
                    finally { _guessLock.Release(); }
 | 
			
		||||
                    if (!guess) return;
 | 
			
		||||
                    triviaCancelSource.Cancel();
 | 
			
		||||
 | 
			
		||||
                    
 | 
			
		||||
                    if (Users[guildUser] == WinRequirement) {
 | 
			
		||||
                        ShouldStopGame = true;
 | 
			
		||||
                        await channel.SendConfirmAsync("Trivia Game", $"{guildUser.Mention} guessed it and WON the game! The answer was: **{CurrentQuestion.Answer}**").ConfigureAwait(false);
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
                    await channel.SendConfirmAsync("Trivia Game", $"{guildUser.Mention} guessed it! The answer was: **{CurrentQuestion.Answer}**").ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
            });
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
                finally { _guessLock.Release(); }
 | 
			
		||||
                if (!guess) return;
 | 
			
		||||
                triviaCancelSource.Cancel();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                if (Users[guildUser] == WinRequirement)
 | 
			
		||||
                {
 | 
			
		||||
                    ShouldStopGame = true;
 | 
			
		||||
                    await channel.SendConfirmAsync("Trivia Game", $"{guildUser.Mention} guessed it and WON the game! The answer was: **{CurrentQuestion.Answer}**").ConfigureAwait(false);
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
                await channel.SendConfirmAsync("Trivia Game", $"{guildUser.Mention} guessed it! The answer was: **{CurrentQuestion.Answer}**").ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex) { _log.Warn(ex); }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string GetLeaderboard()
 | 
			
		||||
 
 | 
			
		||||
@@ -73,7 +73,7 @@ namespace NadekoBot.Modules.Music.Classes
 | 
			
		||||
        public bool Autoplay { get; set; } = false;
 | 
			
		||||
        public uint MaxQueueSize { get; set; } = 0;
 | 
			
		||||
 | 
			
		||||
        private ConcurrentQueue<Action> actionQueue { get; set; } = new ConcurrentQueue<Action>();
 | 
			
		||||
        private ConcurrentQueue<Action> actionQueue { get; } = new ConcurrentQueue<Action>();
 | 
			
		||||
 | 
			
		||||
        public string PrettyVolume => $"🔉 {(int)(Volume * 100)}%";
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -36,17 +36,15 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
            Directory.CreateDirectory(MusicDataPath);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Task Client_UserVoiceStateUpdated(IUser iusr, IVoiceState oldState, IVoiceState newState)
 | 
			
		||||
        private void Client_UserVoiceStateUpdated(IUser iusr, IVoiceState oldState, IVoiceState newState)
 | 
			
		||||
        {
 | 
			
		||||
            var usr = iusr as IGuildUser;
 | 
			
		||||
            if (usr == null ||
 | 
			
		||||
                oldState.VoiceChannel == newState.VoiceChannel)
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                return;
 | 
			
		||||
            MusicPlayer player;
 | 
			
		||||
            if (!MusicPlayers.TryGetValue(usr.Guild.Id, out player))
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                return;
 | 
			
		||||
            if ((player.PlaybackVoiceChannel == newState.VoiceChannel && //if joined first, and player paused, unpause 
 | 
			
		||||
                    player.Paused &&
 | 
			
		||||
                    player.PlaybackVoiceChannel.GetUsers().Count == 2) ||  // keep in mind bot is in the channel (+1)
 | 
			
		||||
@@ -56,7 +54,7 @@ namespace NadekoBot.Modules.Music
 | 
			
		||||
            {
 | 
			
		||||
                player.TogglePause();
 | 
			
		||||
            }
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
@@ -903,7 +901,7 @@ $"{("tracks".SnPl(musicPlayer.Playlist.Count))} | {(int)total.TotalHours}h {tota
 | 
			
		||||
            }
 | 
			
		||||
            catch (PlaylistFullException)
 | 
			
		||||
            {
 | 
			
		||||
                try { await textCh.SendConfirmAsync($"🎵 Queue is full at **{musicPlayer.MaxQueueSize}/{musicPlayer.MaxQueueSize}**. "); } catch { }
 | 
			
		||||
                try { await textCh.SendConfirmAsync($"🎵 Queue is full at **{musicPlayer.MaxQueueSize}/{musicPlayer.MaxQueueSize}**."); } catch { }
 | 
			
		||||
                throw;
 | 
			
		||||
            }
 | 
			
		||||
            if (!silent)
 | 
			
		||||
 
 | 
			
		||||
@@ -28,40 +28,34 @@ namespace NadekoBot.Modules.Searches
 | 
			
		||||
                TranslatedChannels = new ConcurrentDictionary<ulong, bool>();
 | 
			
		||||
                UserLanguages = new ConcurrentDictionary<UserChannelPair, string>();
 | 
			
		||||
 | 
			
		||||
                NadekoBot.Client.MessageReceived += (msg) =>
 | 
			
		||||
                NadekoBot.Client.MessageReceived += async (msg) =>
 | 
			
		||||
                {
 | 
			
		||||
                    var umsg = msg as IUserMessage;
 | 
			
		||||
                    if(umsg == null)
 | 
			
		||||
                        return Task.CompletedTask;
 | 
			
		||||
                    if (umsg == null)
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                    bool autoDelete;
 | 
			
		||||
                    if (!TranslatedChannels.TryGetValue(umsg.Channel.Id, out autoDelete))
 | 
			
		||||
                        return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                    var t = Task.Run(async () =>
 | 
			
		||||
                        return;
 | 
			
		||||
                    var key = new UserChannelPair()
 | 
			
		||||
                    {
 | 
			
		||||
                        var key = new UserChannelPair()
 | 
			
		||||
                        {
 | 
			
		||||
                            UserId = umsg.Author.Id,
 | 
			
		||||
                            ChannelId = umsg.Channel.Id,
 | 
			
		||||
                        };
 | 
			
		||||
                        UserId = umsg.Author.Id,
 | 
			
		||||
                        ChannelId = umsg.Channel.Id,
 | 
			
		||||
                    };
 | 
			
		||||
 | 
			
		||||
                        string langs;
 | 
			
		||||
                        if (!UserLanguages.TryGetValue(key, out langs))
 | 
			
		||||
                            return;
 | 
			
		||||
                    string langs;
 | 
			
		||||
                    if (!UserLanguages.TryGetValue(key, out langs))
 | 
			
		||||
                        return;
 | 
			
		||||
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            var text = await TranslateInternal(umsg, langs, umsg.Resolve(UserMentionHandling.Ignore), true)
 | 
			
		||||
                                                .ConfigureAwait(false);
 | 
			
		||||
                            if (autoDelete)
 | 
			
		||||
                                try { await umsg.DeleteAsync().ConfigureAwait(false); } catch { }
 | 
			
		||||
                            await umsg.Channel.SendConfirmAsync($"{umsg.Author.Mention} `:` "+text.Replace("<@ ", "<@").Replace("<@! ", "<@!")).ConfigureAwait(false);
 | 
			
		||||
                        }
 | 
			
		||||
                        catch { }
 | 
			
		||||
 | 
			
		||||
                    });
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        var text = await TranslateInternal(umsg, langs, umsg.Resolve(UserMentionHandling.Ignore), true)
 | 
			
		||||
                                            .ConfigureAwait(false);
 | 
			
		||||
                        if (autoDelete)
 | 
			
		||||
                            try { await umsg.DeleteAsync().ConfigureAwait(false); } catch { }
 | 
			
		||||
                        await umsg.Channel.SendConfirmAsync($"{umsg.Author.Mention} `:` " + text.Replace("<@ ", "<@").Replace("<@! ", "<@!")).ConfigureAwait(false);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch {  }
 | 
			
		||||
                };
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -95,5 +95,31 @@ namespace NadekoBot.Modules.Utility
 | 
			
		||||
                .WithOkColor();
 | 
			
		||||
            await msg.Channel.EmbedAsync(embed.Build()).ConfigureAwait(false);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        [NadekoCommand, Usage, Description, Aliases]
 | 
			
		||||
        [RequireContext(ContextType.Guild)]
 | 
			
		||||
        [OwnerOnly]
 | 
			
		||||
        public async Task Activity(IUserMessage imsg, int page = 1)
 | 
			
		||||
        {
 | 
			
		||||
            const int activityPerPage = 15;
 | 
			
		||||
            page -= 1;
 | 
			
		||||
 | 
			
		||||
            if (page < 0)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            int startCount = page * activityPerPage;
 | 
			
		||||
 | 
			
		||||
            StringBuilder str = new StringBuilder();
 | 
			
		||||
            foreach (var kvp in NadekoBot.CommandHandler.UserMessagesSent.OrderByDescending(kvp => kvp.Value).Skip(page*activityPerPage).Take(activityPerPage))
 | 
			
		||||
            {
 | 
			
		||||
                str.AppendLine($"`{++startCount}.` **{kvp.Key}** [{kvp.Value/NadekoBot.Stats.GetUptime().TotalSeconds:F2}/s] - {kvp.Value} total");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            await imsg.Channel.EmbedAsync(new EmbedBuilder().WithTitle($"Activity Page #{page}")
 | 
			
		||||
                .WithOkColor()
 | 
			
		||||
                .WithFooter(efb => efb.WithText($"{NadekoBot.CommandHandler.UserMessagesSent.Count} users total."))
 | 
			
		||||
                .WithDescription(str.ToString())
 | 
			
		||||
                .Build());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										27
									
								
								src/NadekoBot/Resources/CommandStrings.Designer.cs
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										27
									
								
								src/NadekoBot/Resources/CommandStrings.Designer.cs
									
									
									
										generated
									
									
									
								
							@@ -113,6 +113,33 @@ namespace NadekoBot.Resources {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        ///    Looks up a localized string similar to activity.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public static string activity_cmd {
 | 
			
		||||
            get {
 | 
			
		||||
                return ResourceManager.GetString("activity_cmd", resourceCulture);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        ///    Looks up a localized string similar to Checks for spammers..
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public static string activity_desc {
 | 
			
		||||
            get {
 | 
			
		||||
                return ResourceManager.GetString("activity_desc", resourceCulture);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        ///    Looks up a localized string similar to `{0}activity`.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
        public static string activity_usage {
 | 
			
		||||
            get {
 | 
			
		||||
                return ResourceManager.GetString("activity_usage", resourceCulture);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        /// <summary>
 | 
			
		||||
        ///    Looks up a localized string similar to addcustreact acr.
 | 
			
		||||
        /// </summary>
 | 
			
		||||
 
 | 
			
		||||
@@ -2835,4 +2835,13 @@
 | 
			
		||||
  <data name="setmaxplaytime_usage" xml:space="preserve">
 | 
			
		||||
    <value>`{0}smp 0` or `{0}smp 270`</value>
 | 
			
		||||
  </data>
 | 
			
		||||
  <data name="activity_cmd" xml:space="preserve">
 | 
			
		||||
    <value>activity</value>
 | 
			
		||||
  </data>
 | 
			
		||||
  <data name="activity_desc" xml:space="preserve">
 | 
			
		||||
    <value>Checks for spammers.</value>
 | 
			
		||||
  </data>
 | 
			
		||||
  <data name="activity_usage" xml:space="preserve">
 | 
			
		||||
    <value>`{0}activity`</value>
 | 
			
		||||
  </data>
 | 
			
		||||
</root>
 | 
			
		||||
@@ -16,20 +16,15 @@ using NadekoBot.Modules.Help;
 | 
			
		||||
using static NadekoBot.Modules.Administration.Administration;
 | 
			
		||||
using NadekoBot.Modules.CustomReactions;
 | 
			
		||||
using NadekoBot.Modules.Games;
 | 
			
		||||
using System.Collections.Concurrent;
 | 
			
		||||
 | 
			
		||||
namespace NadekoBot.Services
 | 
			
		||||
{
 | 
			
		||||
    public class IGuildUserComparer : IEqualityComparer<IGuildUser>
 | 
			
		||||
    {
 | 
			
		||||
        public bool Equals(IGuildUser x, IGuildUser y)
 | 
			
		||||
        {
 | 
			
		||||
            return x.Id == y.Id;
 | 
			
		||||
        }
 | 
			
		||||
        public bool Equals(IGuildUser x, IGuildUser y) => x.Id == y.Id;
 | 
			
		||||
 | 
			
		||||
        public int GetHashCode(IGuildUser obj)
 | 
			
		||||
        {
 | 
			
		||||
            return obj.Id.GetHashCode();
 | 
			
		||||
        }
 | 
			
		||||
        public int GetHashCode(IGuildUser obj) => obj.Id.GetHashCode();
 | 
			
		||||
    }
 | 
			
		||||
    public class CommandHandler
 | 
			
		||||
    {
 | 
			
		||||
@@ -39,7 +34,10 @@ namespace NadekoBot.Services
 | 
			
		||||
 | 
			
		||||
        private List<IDMChannel> ownerChannels { get; set; }
 | 
			
		||||
 | 
			
		||||
        public event Func<IUserMessage,Command, Task> CommandExecuted = delegate { return Task.CompletedTask; };
 | 
			
		||||
        public event Func<IUserMessage, Command, Task> CommandExecuted = delegate { return Task.CompletedTask; };
 | 
			
		||||
 | 
			
		||||
        //userid/msg count
 | 
			
		||||
        public ConcurrentDictionary<ulong, uint> UserMessagesSent { get; } = new ConcurrentDictionary<ulong, uint>();
 | 
			
		||||
 | 
			
		||||
        public CommandHandler(ShardedDiscordClient client, CommandService commandService)
 | 
			
		||||
        {
 | 
			
		||||
@@ -64,46 +62,30 @@ namespace NadekoBot.Services
 | 
			
		||||
            _client.MessageReceived += MessageReceivedHandler;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Task MessageReceivedHandler(IMessage msg)
 | 
			
		||||
        private async void MessageReceivedHandler(IMessage msg)
 | 
			
		||||
        {
 | 
			
		||||
            var usrMsg = msg as IUserMessage;
 | 
			
		||||
            if (usrMsg == null)
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            if (!usrMsg.IsAuthor())
 | 
			
		||||
                UserMessagesSent.AddOrUpdate(usrMsg.Author.Id, 1, (key, old) => ++old);
 | 
			
		||||
 | 
			
		||||
            if (usrMsg.Author.IsBot || !NadekoBot.Ready) //no bots
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
                return;
 | 
			
		||||
            var sw = new Stopwatch();
 | 
			
		||||
            sw.Start();
 | 
			
		||||
 | 
			
		||||
            var throwaway = Task.Run(async () =>
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                var sw = new Stopwatch();
 | 
			
		||||
                sw.Start();
 | 
			
		||||
                var guild = (msg.Channel as ITextChannel)?.Guild;
 | 
			
		||||
 | 
			
		||||
                try
 | 
			
		||||
                if (guild != null && guild.OwnerId != usrMsg.Author.Id)
 | 
			
		||||
                {
 | 
			
		||||
                    var guild = (msg.Channel as ITextChannel)?.Guild;
 | 
			
		||||
 | 
			
		||||
                    if (guild != null && guild.OwnerId != usrMsg.Author.Id)
 | 
			
		||||
                    if (Permissions.FilterCommands.InviteFilteringChannels.Contains(usrMsg.Channel.Id) ||
 | 
			
		||||
                        Permissions.FilterCommands.InviteFilteringServers.Contains(guild.Id))
 | 
			
		||||
                    {
 | 
			
		||||
                        if (Permissions.FilterCommands.InviteFilteringChannels.Contains(usrMsg.Channel.Id) ||
 | 
			
		||||
                            Permissions.FilterCommands.InviteFilteringServers.Contains(guild.Id))
 | 
			
		||||
                        {
 | 
			
		||||
                            if (usrMsg.Content.IsDiscordInvite())
 | 
			
		||||
                            {
 | 
			
		||||
                                try
 | 
			
		||||
                                {
 | 
			
		||||
                                    await usrMsg.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
                                    return;
 | 
			
		||||
                                }
 | 
			
		||||
                                catch (HttpException ex)
 | 
			
		||||
                                {
 | 
			
		||||
                                    _log.Warn("I do not have permission to filter invites in channel with id " + usrMsg.Channel.Id, ex);
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        var filteredWords = Permissions.FilterCommands.FilteredWordsForChannel(usrMsg.Channel.Id, guild.Id).Concat(Permissions.FilterCommands.FilteredWordsForServer(guild.Id));
 | 
			
		||||
                        var wordsInMessage = usrMsg.Content.ToLowerInvariant().Split(' ');
 | 
			
		||||
                        if (filteredWords.Any(w => wordsInMessage.Contains(w)))
 | 
			
		||||
                        if (usrMsg.Content.IsDiscordInvite())
 | 
			
		||||
                        {
 | 
			
		||||
                            try
 | 
			
		||||
                            {
 | 
			
		||||
@@ -112,105 +94,118 @@ namespace NadekoBot.Services
 | 
			
		||||
                            }
 | 
			
		||||
                            catch (HttpException ex)
 | 
			
		||||
                            {
 | 
			
		||||
                                _log.Warn("I do not have permission to filter words in channel with id " + usrMsg.Channel.Id, ex);
 | 
			
		||||
                                _log.Warn("I do not have permission to filter invites in channel with id " + usrMsg.Channel.Id, ex);
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    BlacklistItem blacklistedItem;
 | 
			
		||||
                    if ((blacklistedItem = Permissions.BlacklistCommands.BlacklistedItems.FirstOrDefault(bi =>
 | 
			
		||||
                         (bi.Type == BlacklistItem.BlacklistType.Server && bi.ItemId == guild?.Id) ||
 | 
			
		||||
                         (bi.Type == BlacklistItem.BlacklistType.Channel && bi.ItemId == msg.Channel.Id) ||
 | 
			
		||||
                         (bi.Type == BlacklistItem.BlacklistType.User && bi.ItemId == usrMsg.Author.Id))) != null)
 | 
			
		||||
                    var filteredWords = Permissions.FilterCommands.FilteredWordsForChannel(usrMsg.Channel.Id, guild.Id).Concat(Permissions.FilterCommands.FilteredWordsForServer(guild.Id));
 | 
			
		||||
                    var wordsInMessage = usrMsg.Content.ToLowerInvariant().Split(' ');
 | 
			
		||||
                    if (filteredWords.Any(w => wordsInMessage.Contains(w)))
 | 
			
		||||
                    {
 | 
			
		||||
                        return;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        var cleverbotExecuted = await Games.CleverBotCommands.TryAsk(usrMsg);
 | 
			
		||||
 | 
			
		||||
                        if (cleverbotExecuted)
 | 
			
		||||
                            return;
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (Exception ex) { _log.Warn(ex, "Error in cleverbot"); }
 | 
			
		||||
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        // maybe this message is a custom reaction
 | 
			
		||||
                        var crExecuted = await CustomReactions.TryExecuteCustomReaction(usrMsg).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                        //if it was, don't execute the command
 | 
			
		||||
                        if (crExecuted)
 | 
			
		||||
                            return;
 | 
			
		||||
                    }
 | 
			
		||||
                    catch { }
 | 
			
		||||
 | 
			
		||||
                    var t = await ExecuteCommand(usrMsg, usrMsg.Content, guild, usrMsg.Author, MultiMatchHandling.Best);
 | 
			
		||||
                    var command = t.Item1;
 | 
			
		||||
                    var permCache = t.Item2;
 | 
			
		||||
                    var result = t.Item3;
 | 
			
		||||
                    sw.Stop();
 | 
			
		||||
                    var channel = (usrMsg.Channel as ITextChannel);
 | 
			
		||||
                    if (result.IsSuccess)
 | 
			
		||||
                    {
 | 
			
		||||
                        await CommandExecuted(usrMsg, command);
 | 
			
		||||
                        _log.Info("Command Executed after {4}s\n\t" +
 | 
			
		||||
                                    "User: {0}\n\t" +
 | 
			
		||||
                                    "Server: {1}\n\t" +
 | 
			
		||||
                                    "Channel: {2}\n\t" +
 | 
			
		||||
                                    "Message: {3}",
 | 
			
		||||
                                    usrMsg.Author + " [" + usrMsg.Author.Id + "]", // {0}
 | 
			
		||||
                                    (channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1}
 | 
			
		||||
                                    (channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
 | 
			
		||||
                                    usrMsg.Content, // {3}
 | 
			
		||||
                                    sw.Elapsed.TotalSeconds // {4}
 | 
			
		||||
                                    );
 | 
			
		||||
                    }
 | 
			
		||||
                    else if (!result.IsSuccess && result.Error != CommandError.UnknownCommand)
 | 
			
		||||
                    {
 | 
			
		||||
                        _log.Warn("Command Errored after {5}s\n\t" +
 | 
			
		||||
                                    "User: {0}\n\t" +
 | 
			
		||||
                                    "Server: {1}\n\t" +
 | 
			
		||||
                                    "Channel: {2}\n\t" +
 | 
			
		||||
                                    "Message: {3}\n\t" +
 | 
			
		||||
                                    "Error: {4}",
 | 
			
		||||
                                    usrMsg.Author + " [" + usrMsg.Author.Id + "]", // {0}
 | 
			
		||||
                                    (channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1}
 | 
			
		||||
                                    (channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
 | 
			
		||||
                                    usrMsg.Content,// {3}
 | 
			
		||||
                                    result.ErrorReason, // {4}
 | 
			
		||||
                                    sw.Elapsed.TotalSeconds // {5}
 | 
			
		||||
                                    );
 | 
			
		||||
                        if (guild != null && command != null && result.Error == CommandError.Exception)
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            if (permCache != null && permCache.Verbose)
 | 
			
		||||
                                try { await msg.Channel.SendMessageAsync("⚠️ " + result.ErrorReason).ConfigureAwait(false); } catch { }
 | 
			
		||||
                            await usrMsg.DeleteAsync().ConfigureAwait(false);
 | 
			
		||||
                            return;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        if (msg.Channel is IPrivateChannel)
 | 
			
		||||
                        catch (HttpException ex)
 | 
			
		||||
                        {
 | 
			
		||||
                            //rofl, gotta do this to prevent this message from occuring on polls
 | 
			
		||||
                            int vote;
 | 
			
		||||
                            if (int.TryParse(msg.Content, out vote)) return; 
 | 
			
		||||
 | 
			
		||||
                            await msg.Channel.SendMessageAsync(Help.DMHelpString).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                            await DMForwardCommands.HandleDMForwarding(msg, ownerChannels);
 | 
			
		||||
                            _log.Warn("I do not have permission to filter words in channel with id " + usrMsg.Channel.Id, ex);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex)
 | 
			
		||||
 | 
			
		||||
                BlacklistItem blacklistedItem;
 | 
			
		||||
                if ((blacklistedItem = Permissions.BlacklistCommands.BlacklistedItems.FirstOrDefault(bi =>
 | 
			
		||||
                     (bi.Type == BlacklistItem.BlacklistType.Server && bi.ItemId == guild?.Id) ||
 | 
			
		||||
                     (bi.Type == BlacklistItem.BlacklistType.Channel && bi.ItemId == msg.Channel.Id) ||
 | 
			
		||||
                     (bi.Type == BlacklistItem.BlacklistType.User && bi.ItemId == usrMsg.Author.Id))) != null)
 | 
			
		||||
                {
 | 
			
		||||
                    _log.Warn(ex, "Error in CommandHandler");
 | 
			
		||||
                    if (ex.InnerException != null)
 | 
			
		||||
                        _log.Warn(ex.InnerException, "Inner Exception of the error in CommandHandler");
 | 
			
		||||
                    return;
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return Task.CompletedTask;
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    var cleverbotExecuted = await Games.CleverBotCommands.TryAsk(usrMsg);
 | 
			
		||||
 | 
			
		||||
                    if (cleverbotExecuted)
 | 
			
		||||
                        return;
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception ex) { _log.Warn(ex, "Error in cleverbot"); }
 | 
			
		||||
 | 
			
		||||
                try
 | 
			
		||||
                {
 | 
			
		||||
                    // maybe this message is a custom reaction
 | 
			
		||||
                    var crExecuted = await CustomReactions.TryExecuteCustomReaction(usrMsg).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                    //if it was, don't execute the command
 | 
			
		||||
                    if (crExecuted)
 | 
			
		||||
                        return;
 | 
			
		||||
                }
 | 
			
		||||
                catch { }
 | 
			
		||||
 | 
			
		||||
                var t = await ExecuteCommand(usrMsg, usrMsg.Content, guild, usrMsg.Author, MultiMatchHandling.Best);
 | 
			
		||||
                var command = t.Item1;
 | 
			
		||||
                var permCache = t.Item2;
 | 
			
		||||
                var result = t.Item3;
 | 
			
		||||
                sw.Stop();
 | 
			
		||||
                var channel = (usrMsg.Channel as ITextChannel);
 | 
			
		||||
                if (result.IsSuccess)
 | 
			
		||||
                {
 | 
			
		||||
                    await CommandExecuted(usrMsg, command);
 | 
			
		||||
                    _log.Info("Command Executed after {4}s\n\t" +
 | 
			
		||||
                                "User: {0}\n\t" +
 | 
			
		||||
                                "Server: {1}\n\t" +
 | 
			
		||||
                                "Channel: {2}\n\t" +
 | 
			
		||||
                                "Message: {3}",
 | 
			
		||||
                                usrMsg.Author + " [" + usrMsg.Author.Id + "]", // {0}
 | 
			
		||||
                                (channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1}
 | 
			
		||||
                                (channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
 | 
			
		||||
                                usrMsg.Content, // {3}
 | 
			
		||||
                                sw.Elapsed.TotalSeconds // {4}
 | 
			
		||||
                                );
 | 
			
		||||
                }
 | 
			
		||||
                else if (!result.IsSuccess && result.Error != CommandError.UnknownCommand)
 | 
			
		||||
                {
 | 
			
		||||
                    _log.Warn("Command Errored after {5}s\n\t" +
 | 
			
		||||
                                "User: {0}\n\t" +
 | 
			
		||||
                                "Server: {1}\n\t" +
 | 
			
		||||
                                "Channel: {2}\n\t" +
 | 
			
		||||
                                "Message: {3}\n\t" +
 | 
			
		||||
                                "Error: {4}",
 | 
			
		||||
                                usrMsg.Author + " [" + usrMsg.Author.Id + "]", // {0}
 | 
			
		||||
                                (channel == null ? "PRIVATE" : channel.Guild.Name + " [" + channel.Guild.Id + "]"), // {1}
 | 
			
		||||
                                (channel == null ? "PRIVATE" : channel.Name + " [" + channel.Id + "]"), // {2}
 | 
			
		||||
                                usrMsg.Content,// {3}
 | 
			
		||||
                                result.ErrorReason, // {4}
 | 
			
		||||
                                sw.Elapsed.TotalSeconds // {5}
 | 
			
		||||
                                );
 | 
			
		||||
                    if (guild != null && command != null && result.Error == CommandError.Exception)
 | 
			
		||||
                    {
 | 
			
		||||
                        if (permCache != null && permCache.Verbose)
 | 
			
		||||
                            try { await msg.Channel.SendMessageAsync("⚠️ " + result.ErrorReason).ConfigureAwait(false); } catch { }
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                else
 | 
			
		||||
                {
 | 
			
		||||
                    if (msg.Channel is IPrivateChannel)
 | 
			
		||||
                    {
 | 
			
		||||
                        //rofl, gotta do this to prevent this message from occuring on polls
 | 
			
		||||
                        int vote;
 | 
			
		||||
                        if (int.TryParse(msg.Content, out vote)) return;
 | 
			
		||||
 | 
			
		||||
                        await msg.Channel.SendMessageAsync(Help.DMHelpString).ConfigureAwait(false);
 | 
			
		||||
 | 
			
		||||
                        await DMForwardCommands.HandleDMForwarding(msg, ownerChannels);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch (Exception ex)
 | 
			
		||||
            {
 | 
			
		||||
                _log.Warn(ex, "Error in CommandHandler");
 | 
			
		||||
                if (ex.InnerException != null)
 | 
			
		||||
                    _log.Warn(ex.InnerException, "Inner Exception of the error in CommandHandler");
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<Tuple<Command, PermissionCache, IResult>> ExecuteCommand(IUserMessage message, string input, IGuild guild, IUser user, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Best) {
 | 
			
		||||
 
 | 
			
		||||
@@ -13,20 +13,20 @@ namespace NadekoBot
 | 
			
		||||
        private DiscordSocketConfig discordSocketConfig;
 | 
			
		||||
        private Logger _log { get; }
 | 
			
		||||
 | 
			
		||||
        public event Func<IGuildUser, Task> UserJoined = delegate { return Task.CompletedTask; };
 | 
			
		||||
        public event Func<IMessage, Task> MessageReceived = delegate { return Task.CompletedTask; };
 | 
			
		||||
        public event Func<IGuildUser, Task> UserLeft = delegate { return Task.CompletedTask; };
 | 
			
		||||
        public event Func<IGuildUser, IGuildUser, Task> UserUpdated = delegate { return Task.CompletedTask; };
 | 
			
		||||
        public event Func<Optional<IMessage>, IMessage, Task> MessageUpdated = delegate { return Task.CompletedTask; };
 | 
			
		||||
        public event Func<ulong, Optional<IMessage>, Task> MessageDeleted = delegate { return Task.CompletedTask; };
 | 
			
		||||
        public event Func<IUser, IGuild, Task> UserBanned = delegate { return Task.CompletedTask; };
 | 
			
		||||
        public event Func<IUser, IGuild, Task> UserUnbanned = delegate { return Task.CompletedTask; };
 | 
			
		||||
        public event Func<IGuildUser, IPresence, IPresence, Task> UserPresenceUpdated = delegate { return Task.CompletedTask; };
 | 
			
		||||
        public event Func<IUser, IVoiceState, IVoiceState, Task> UserVoiceStateUpdated = delegate { return Task.CompletedTask; };
 | 
			
		||||
        public event Func<IChannel, Task> ChannelCreated = delegate { return Task.CompletedTask; };
 | 
			
		||||
        public event Func<IChannel, Task> ChannelDestroyed = delegate { return Task.CompletedTask; };
 | 
			
		||||
        public event Func<IChannel, IChannel, Task> ChannelUpdated = delegate { return Task.CompletedTask; };
 | 
			
		||||
        public event Func<Exception, Task> Disconnected = delegate { return Task.CompletedTask; };
 | 
			
		||||
        public event Action<IGuildUser> UserJoined = delegate {  };
 | 
			
		||||
        public event Action<IMessage> MessageReceived = delegate {  };
 | 
			
		||||
        public event Action<IGuildUser> UserLeft = delegate {  };
 | 
			
		||||
        public event Action<IGuildUser, IGuildUser> UserUpdated = delegate {  };
 | 
			
		||||
        public event Action<Optional<IMessage>, IMessage> MessageUpdated = delegate {  };
 | 
			
		||||
        public event Action<ulong, Optional<IMessage>> MessageDeleted = delegate {  };
 | 
			
		||||
        public event Action<IUser, IGuild> UserBanned = delegate {  };
 | 
			
		||||
        public event Action<IUser, IGuild> UserUnbanned = delegate {  };
 | 
			
		||||
        public event Action<IGuildUser, IPresence, IPresence> UserPresenceUpdated = delegate {  };
 | 
			
		||||
        public event Action<IUser, IVoiceState, IVoiceState> UserVoiceStateUpdated = delegate {  };
 | 
			
		||||
        public event Action<IChannel> ChannelCreated = delegate {  };
 | 
			
		||||
        public event Action<IChannel> ChannelDestroyed = delegate {  };
 | 
			
		||||
        public event Action<IChannel, IChannel> ChannelUpdated = delegate { };
 | 
			
		||||
        public event Action<Exception> Disconnected = delegate {  };
 | 
			
		||||
 | 
			
		||||
        private IReadOnlyList<DiscordSocketClient> Clients { get; }
 | 
			
		||||
 | 
			
		||||
@@ -41,19 +41,19 @@ namespace NadekoBot
 | 
			
		||||
                discordSocketConfig.ShardId = i;
 | 
			
		||||
                var client = new DiscordSocketClient(discordSocketConfig);
 | 
			
		||||
                clientList.Add(client);
 | 
			
		||||
                client.UserJoined += async arg1 => await UserJoined(arg1);
 | 
			
		||||
                client.MessageReceived += async arg1 => await MessageReceived(arg1);
 | 
			
		||||
                client.UserLeft += async arg1 => await UserLeft(arg1);
 | 
			
		||||
                client.UserUpdated += async (arg1, gu2) => await UserUpdated(arg1, gu2);
 | 
			
		||||
                client.MessageUpdated += async (arg1, m2) => await MessageUpdated(arg1, m2);
 | 
			
		||||
                client.MessageDeleted += async (arg1, arg2) => await MessageDeleted(arg1, arg2);
 | 
			
		||||
                client.UserBanned += async (arg1, arg2) => await UserBanned(arg1, arg2);
 | 
			
		||||
                client.UserUnbanned += async (arg1, arg2) => await UserUnbanned(arg1, arg2);
 | 
			
		||||
                client.UserPresenceUpdated += async (arg1, arg2, arg3) => await UserPresenceUpdated(arg1, arg2, arg3);
 | 
			
		||||
                client.UserVoiceStateUpdated += async (arg1, arg2, arg3) => await UserVoiceStateUpdated(arg1, arg2, arg3);
 | 
			
		||||
                client.ChannelCreated += async arg => await ChannelCreated(arg);
 | 
			
		||||
                client.ChannelDestroyed += async arg => await ChannelDestroyed(arg);
 | 
			
		||||
                client.ChannelUpdated += async (arg1, arg2) => await ChannelUpdated(arg1, arg2);
 | 
			
		||||
                client.UserJoined += arg1 => { UserJoined(arg1); return Task.CompletedTask; };
 | 
			
		||||
                client.MessageReceived += arg1 => { MessageReceived(arg1); return Task.CompletedTask; };
 | 
			
		||||
                client.UserLeft += arg1 => { UserLeft(arg1); return Task.CompletedTask; };
 | 
			
		||||
                client.UserUpdated += (arg1, gu2) => { UserUpdated(arg1, gu2); return Task.CompletedTask; };
 | 
			
		||||
                client.MessageUpdated += (arg1, m2) => { MessageUpdated(arg1, m2); return Task.CompletedTask; };
 | 
			
		||||
                client.MessageDeleted += (arg1, arg2) => { MessageDeleted(arg1, arg2); return Task.CompletedTask; };
 | 
			
		||||
                client.UserBanned += (arg1, arg2) => { UserBanned(arg1, arg2); return Task.CompletedTask; };
 | 
			
		||||
                client.UserUnbanned += (arg1, arg2) => { UserUnbanned(arg1, arg2); return Task.CompletedTask; };
 | 
			
		||||
                client.UserPresenceUpdated += (arg1, arg2, arg3) => { UserPresenceUpdated(arg1, arg2, arg3); return Task.CompletedTask; };
 | 
			
		||||
                client.UserVoiceStateUpdated += (arg1, arg2, arg3) => { UserVoiceStateUpdated(arg1, arg2, arg3); return Task.CompletedTask; };
 | 
			
		||||
                client.ChannelCreated += arg => { ChannelCreated(arg); return Task.CompletedTask; };
 | 
			
		||||
                client.ChannelDestroyed += arg => { ChannelDestroyed(arg); return Task.CompletedTask; };
 | 
			
		||||
                client.ChannelUpdated += (arg1, arg2) => { ChannelUpdated(arg1, arg2); return Task.CompletedTask; };
 | 
			
		||||
 | 
			
		||||
                _log.Info($"Shard #{i} initialized.");
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user