commit
024ecf521a
@ -1 +1 @@
|
||||
Subproject commit fa2568bc312ba35f1518e47601c62fccdb949731
|
||||
Subproject commit b9f767337d2b7c07ed76eb83c3bc5030109d5238
|
24
src/NadekoBot/DataStructures/ExecuteCommandResult.cs
Normal file
24
src/NadekoBot/DataStructures/ExecuteCommandResult.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using Discord.Commands;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static NadekoBot.Modules.Permissions.Permissions;
|
||||
|
||||
namespace NadekoBot.DataStructures
|
||||
{
|
||||
public struct ExecuteCommandResult
|
||||
{
|
||||
public readonly CommandInfo CommandInfo;
|
||||
public readonly PermissionCache PermissionCache;
|
||||
public readonly IResult Result;
|
||||
|
||||
public ExecuteCommandResult(CommandInfo commandInfo, PermissionCache cache, IResult result)
|
||||
{
|
||||
this.CommandInfo = commandInfo;
|
||||
this.PermissionCache = cache;
|
||||
this.Result = result;
|
||||
}
|
||||
}
|
||||
}
|
@ -78,7 +78,10 @@ namespace NadekoBot.Modules.Administration
|
||||
_client.UserPresenceUpdated += _client_UserPresenceUpdated;
|
||||
_client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated;
|
||||
_client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated_TTS;
|
||||
_client.GuildUserUpdated += _client_GuildUserUpdated;
|
||||
#if !GLOBAL_NADEKO
|
||||
_client.UserUpdated += _client_UserUpdated;
|
||||
#endif
|
||||
|
||||
_client.ChannelCreated += _client_ChannelCreated;
|
||||
_client.ChannelDestroyed += _client_ChannelDestroyed;
|
||||
@ -88,6 +91,38 @@ namespace NadekoBot.Modules.Administration
|
||||
MuteCommands.UserUnmuted += MuteCommands_UserUnmuted;
|
||||
}
|
||||
|
||||
private static async void _client_UserUpdated(SocketUser before, SocketUser after)
|
||||
{
|
||||
try
|
||||
{
|
||||
var str = "";
|
||||
if (before.Username != after.Username)
|
||||
str = $"👤__**{before.Username}#{before.Discriminator}**__ **| Name Changed |** 🆔 `{before.Id}`\n\t\t`New:` **{after.ToString()}**";
|
||||
else if (before.AvatarUrl != after.AvatarUrl)
|
||||
str = $"👤__**{before.Username}#{before.Discriminator}**__ **| Avatar Changed |** 🆔 `{before.Id}`\n\t🖼 {await NadekoBot.Google.ShortenUrl(before.AvatarUrl)} `=>` {await NadekoBot.Google.ShortenUrl(after.AvatarUrl)}";
|
||||
|
||||
if (string.IsNullOrWhiteSpace(str))
|
||||
return;
|
||||
|
||||
var guildsMemberOf = NadekoBot.Client.GetGuilds().Where(g => g.Users.Select(u => u.Id).Contains(before.Id)).ToList();
|
||||
foreach (var g in guildsMemberOf)
|
||||
{
|
||||
LogSetting logSetting;
|
||||
if (!GuildLogSettings.TryGetValue(g.Id, out logSetting)
|
||||
|| (logSetting.UserUpdatedId == null))
|
||||
return;
|
||||
|
||||
ITextChannel logChannel;
|
||||
if ((logChannel = await TryGetLogChannel(g, logSetting, LogType.UserUpdated)) == null)
|
||||
return;
|
||||
|
||||
try { await logChannel.SendMessageAsync(str).ConfigureAwait(false); } catch { }
|
||||
}
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
}
|
||||
|
||||
private static async void _client_UserVoiceStateUpdated_TTS(SocketUser iusr, SocketVoiceState before, SocketVoiceState after)
|
||||
{
|
||||
try
|
||||
@ -228,17 +263,10 @@ namespace NadekoBot.Modules.Administration
|
||||
catch (Exception ex) { _log.Warn(ex); }
|
||||
}
|
||||
|
||||
private static async void _client_UserUpdated(SocketUser uBefore, SocketUser uAfter)
|
||||
private static async void _client_GuildUserUpdated(SocketGuildUser before, SocketGuildUser after)
|
||||
{
|
||||
try
|
||||
{
|
||||
var before = uBefore as SocketGuildUser;
|
||||
if (before == null)
|
||||
return;
|
||||
var after = uAfter as SocketGuildUser;
|
||||
if (after == null)
|
||||
return;
|
||||
|
||||
LogSetting logSetting;
|
||||
if (!GuildLogSettings.TryGetValue(before.Guild.Id, out logSetting)
|
||||
|| (logSetting.UserUpdatedId == null))
|
||||
@ -247,30 +275,25 @@ namespace NadekoBot.Modules.Administration
|
||||
ITextChannel logChannel;
|
||||
if ((logChannel = await TryGetLogChannel(before.Guild, logSetting, LogType.UserUpdated)) == null)
|
||||
return;
|
||||
string str = $"🕔`{prettyCurrentTime}`";
|
||||
|
||||
if (before.Username != after.Username)
|
||||
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}**";
|
||||
else if (before.AvatarUrl != after.AvatarUrl)
|
||||
str += $"👤__**{before.Username}#{before.Discriminator}**__ **| Avatar Changed |** 🆔 `{before.Id}`\n\t🖼 {await NadekoBot.Google.ShortenUrl(before.AvatarUrl)} `=>` {await NadekoBot.Google.ShortenUrl(after.AvatarUrl)}";
|
||||
var str = "";
|
||||
if (before.Nickname != after.Nickname)
|
||||
str = $"👤__**{before.Username}#{before.Discriminator}**__ **| Nickname Changed |** 🆔 `{before.Id}`\n\t\t`Old:` **{before.Nickname}**\n\t\t`New:` **{after.Nickname}**";
|
||||
else if (!before.RoleIds.SequenceEqual(after.RoleIds))
|
||||
{
|
||||
if (before.RoleIds.Count < after.RoleIds.Count)
|
||||
{
|
||||
var diffRoles = after.RoleIds.Where(r => !before.RoleIds.Contains(r)).Select(r => "**" + before.Guild.GetRole(r).Name + "**");
|
||||
str += $"👤__**{before.ToString()}**__ **| User's Role Added |** 🆔 `{before.Id}`\n\t✅ {string.Join(", ", diffRoles).SanitizeMentions()}\n\t\t⚔ **`{string.Join(", ", after.GetRoles().Select(r => r.Name)).SanitizeMentions()}`** ⚔";
|
||||
str = $"👤__**{before.ToString()}**__ **| User's Role Added |** 🆔 `{before.Id}`\n\t✅ {string.Join(", ", diffRoles).SanitizeMentions()}\n\t\t⚔ **`{string.Join(", ", after.GetRoles().Select(r => r.Name)).SanitizeMentions()}`** ⚔";
|
||||
}
|
||||
else if (before.RoleIds.Count > after.RoleIds.Count)
|
||||
{
|
||||
var diffRoles = before.RoleIds.Where(r => !after.RoleIds.Contains(r)).Select(r => "**" + before.Guild.GetRole(r).Name + "**");
|
||||
str += $"👤__**{before.ToString()}**__ **| User's Role Removed |** 🆔 `{before.Id}`\n\t🚮 {string.Join(", ", diffRoles).SanitizeMentions()}\n\t\t⚔ **`{string.Join(", ", after.GetRoles().Select(r => r.Name)).SanitizeMentions()}`** ⚔";
|
||||
str = $"👤__**{before.ToString()}**__ **| User's Role Removed |** 🆔 `{before.Id}`\n\t🚮 {string.Join(", ", diffRoles).SanitizeMentions()}\n\t\t⚔ **`{string.Join(", ", after.GetRoles().Select(r => r.Name)).SanitizeMentions()}`** ⚔";
|
||||
}
|
||||
}
|
||||
else
|
||||
return;
|
||||
try { await logChannel.SendMessageAsync(str).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
|
||||
try { await logChannel.SendMessageAsync($"🕔`{prettyCurrentTime}` " + str).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex); }
|
||||
}
|
||||
@ -745,9 +768,9 @@ namespace NadekoBot.Modules.Administration
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
if (action.Value)
|
||||
await channel.SendMessageAsync("✅ Logging all events on this channel.").ConfigureAwait(false);
|
||||
await channel.SendConfirmAsync("Logging all events in this channel.").ConfigureAwait(false);
|
||||
else
|
||||
await channel.SendMessageAsync("ℹ️ Logging disabled.").ConfigureAwait(false);
|
||||
await channel.SendConfirmAsync("Logging disabled.").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -774,9 +797,9 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
|
||||
if (removed == 0)
|
||||
await channel.SendMessageAsync($"🆗 Logging will **now ignore** #⃣ `{channel.Name} ({channel.Id})`").ConfigureAwait(false);
|
||||
await channel.SendConfirmAsync($"Logging will IGNORE **{channel.Mention} ({channel.Id})**").ConfigureAwait(false);
|
||||
else
|
||||
await channel.SendMessageAsync($"ℹ️ Logging will **no longer ignore** #⃣ `{channel.Name} ({channel.Id})`").ConfigureAwait(false);
|
||||
await channel.SendConfirmAsync($"Logging will NOT IGNORE **{channel.Mention} ({channel.Id})**").ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -853,9 +876,9 @@ namespace NadekoBot.Modules.Administration
|
||||
}
|
||||
|
||||
if (channelId != null)
|
||||
await channel.SendMessageAsync($"✅ Logging `{type}` event in #⃣ `{channel.Name} ({channel.Id})`").ConfigureAwait(false);
|
||||
await channel.SendConfirmAsync($"Logging **{type}** event in this channel.").ConfigureAwait(false);
|
||||
else
|
||||
await channel.SendMessageAsync($"ℹ️ Stopped logging `{type}` event.").ConfigureAwait(false);
|
||||
await channel.SendConfirmAsync($"Stopped logging **{type}** event.").ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,8 +71,8 @@ namespace NadekoBot.Modules.Administration
|
||||
|
||||
public static Dictionary<string, Func<string>> PlayingPlaceholders { get; } =
|
||||
new Dictionary<string, Func<string>> {
|
||||
{"%servers%", () => NadekoBot.Client.GetGuilds().Count().ToString()},
|
||||
{"%users%", () => NadekoBot.Client.GetGuilds().Select(s => s.Users.Count).Sum().ToString()},
|
||||
{"%servers%", () => NadekoBot.Client.GetGuildsCount().ToString()},
|
||||
{"%users%", () => NadekoBot.Client.GetGuilds().Sum(s => s.Users.Count).ToString()},
|
||||
{"%playing%", () => {
|
||||
var cnt = Music.Music.MusicPlayers.Count(kvp => kvp.Value.CurrentSong != null);
|
||||
if (cnt != 1) return cnt.ToString();
|
||||
|
@ -20,7 +20,7 @@ namespace NadekoBot.Modules.Administration
|
||||
public async Task Leave([Remainder] string guildStr)
|
||||
{
|
||||
guildStr = guildStr.Trim().ToUpperInvariant();
|
||||
var server = NadekoBot.Client.GetGuilds().FirstOrDefault(g => g.Id.ToString().Trim().ToUpperInvariant() == guildStr) ??
|
||||
var server = NadekoBot.Client.GetGuilds().FirstOrDefault(g => g.Id.ToString() == guildStr) ??
|
||||
NadekoBot.Client.GetGuilds().FirstOrDefault(g => g.Name.Trim().ToUpperInvariant() == guildStr);
|
||||
|
||||
if (server == null)
|
||||
|
@ -26,9 +26,9 @@ namespace NadekoBot.Modules.Gambling
|
||||
if (count == 1)
|
||||
{
|
||||
if (rng.Next(0, 2) == 1)
|
||||
await Context.Channel.SendFileAsync(headsPath, $"{Context.User.Mention} flipped " + Format.Code("Heads") + ".").ConfigureAwait(false);
|
||||
await Context.Channel.SendFileAsync(File.Open(headsPath, FileMode.OpenOrCreate), "heads.jpg", $"{Context.User.Mention} flipped " + Format.Code("Heads") + ".").ConfigureAwait(false);
|
||||
else
|
||||
await Context.Channel.SendFileAsync(tailsPath, $"{Context.User.Mention} flipped " + Format.Code("Tails") + ".").ConfigureAwait(false);
|
||||
await Context.Channel.SendFileAsync(File.Open(tailsPath, FileMode.OpenOrCreate), "tails.jpg", $"{Context.User.Mention} flipped " + Format.Code("Tails") + ".").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
if (count > 10 || count < 1)
|
||||
@ -93,7 +93,7 @@ namespace NadekoBot.Modules.Gambling
|
||||
str = $"{Context.User.Mention}`Better luck next time.`";
|
||||
}
|
||||
|
||||
await Context.Channel.SendFileAsync(imgPathToSend, str).ConfigureAwait(false);
|
||||
await Context.Channel.SendFileAsync(File.Open(imgPathToSend, FileMode.OpenOrCreate), "coin.jpg", str).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -88,10 +88,10 @@ namespace NadekoBot.Modules.Games
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#if !GLOBAL_NADEKO
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireUserPermission(ChannelPermission.ManageMessages)]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
public async Task Cleverbot()
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
@ -120,7 +120,6 @@ namespace NadekoBot.Modules.Games
|
||||
|
||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} Enabled cleverbot on this server.").ConfigureAwait(false);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
@ -12,37 +12,15 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Games.Commands.Hangman
|
||||
{
|
||||
public class HangmanModel
|
||||
{
|
||||
public List<HangmanObject> All { get; set; }
|
||||
public List<HangmanObject> Animals { get; set; }
|
||||
public List<HangmanObject> Countries { get; set; }
|
||||
public List<HangmanObject> Movies { get; set; }
|
||||
public List<HangmanObject> Things { get; set; }
|
||||
}
|
||||
|
||||
public class HangmanTermPool
|
||||
{
|
||||
public enum HangmanTermType
|
||||
{
|
||||
All,
|
||||
Animals,
|
||||
Countries,
|
||||
Movies,
|
||||
Things
|
||||
}
|
||||
|
||||
const string termsPath = "data/hangman.json";
|
||||
public static HangmanModel data { get; }
|
||||
public static IReadOnlyDictionary<string, HangmanObject[]> data { get; }
|
||||
static HangmanTermPool()
|
||||
{
|
||||
try
|
||||
{
|
||||
data = JsonConvert.DeserializeObject<HangmanModel>(File.ReadAllText(termsPath));
|
||||
data.All = data.Animals.Concat(data.Countries)
|
||||
.Concat(data.Movies)
|
||||
.Concat(data.Things)
|
||||
.ToList();
|
||||
data = JsonConvert.DeserializeObject<Dictionary<string, HangmanObject[]>>(File.ReadAllText(termsPath));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -50,23 +28,27 @@ namespace NadekoBot.Modules.Games.Commands.Hangman
|
||||
}
|
||||
}
|
||||
|
||||
public static HangmanObject GetTerm(HangmanTermType type)
|
||||
public static HangmanObject GetTerm(string type)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(type))
|
||||
throw new ArgumentNullException(nameof(type));
|
||||
|
||||
type = type.Trim();
|
||||
|
||||
var rng = new NadekoRandom();
|
||||
switch (type)
|
||||
{
|
||||
case HangmanTermType.Animals:
|
||||
return data.Animals[rng.Next(0, data.Animals.Count)];
|
||||
case HangmanTermType.Countries:
|
||||
return data.Countries[rng.Next(0, data.Countries.Count)];
|
||||
case HangmanTermType.Movies:
|
||||
return data.Movies[rng.Next(0, data.Movies.Count)];
|
||||
case HangmanTermType.Things:
|
||||
return data.Things[rng.Next(0, data.Things.Count)];
|
||||
default:
|
||||
return data.All[rng.Next(0, data.All.Count)];
|
||||
|
||||
if (type == "All") {
|
||||
var keys = data.Keys.ToArray();
|
||||
type = keys[rng.Next(0, keys.Length)];
|
||||
}
|
||||
|
||||
HangmanObject[] termTypes;
|
||||
data.TryGetValue(type, out termTypes);
|
||||
|
||||
if (termTypes.Length == 0)
|
||||
return null;
|
||||
|
||||
return termTypes[rng.Next(0, termTypes.Length)];
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,20 +77,23 @@ namespace NadekoBot.Modules.Games.Commands.Hangman
|
||||
public bool GuessedAll => Guesses.IsSupersetOf(Term.Word.ToUpperInvariant()
|
||||
.Where(c => char.IsLetter(c) || char.IsDigit(c)));
|
||||
|
||||
public HangmanTermPool.HangmanTermType TermType { get; }
|
||||
public string TermType { get; }
|
||||
|
||||
public event Action<HangmanGame> OnEnded;
|
||||
|
||||
public HangmanGame(IMessageChannel channel, HangmanTermPool.HangmanTermType type)
|
||||
public HangmanGame(IMessageChannel channel, string type)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
this.GameChannel = channel;
|
||||
this.TermType = type;
|
||||
this.TermType = type.ToTitleCase();
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
this.Term = HangmanTermPool.GetTerm(TermType);
|
||||
|
||||
if (this.Term == null)
|
||||
throw new KeyNotFoundException("Can't find a term with that type. Use hangmanlist command.");
|
||||
// start listening for answers when game starts
|
||||
NadekoBot.Client.MessageReceived += PotentialGuess;
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ namespace NadekoBot.Modules.Games
|
||||
static HangmanCommands()
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
typesStr = $"`List of \"{NadekoBot.ModulePrefixes[typeof(Games).Name]}hangman\" term types:`\n" + String.Join(", ", Enum.GetNames(typeof(HangmanTermPool.HangmanTermType)));
|
||||
typesStr = $"`List of \"{NadekoBot.ModulePrefixes[typeof(Games).Name]}hangman\" term types:`\n" + String.Join(", ", HangmanTermPool.data.Keys);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -33,7 +33,7 @@ namespace NadekoBot.Modules.Games
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
public async Task Hangman(HangmanTermPool.HangmanTermType type = HangmanTermPool.HangmanTermType.All)
|
||||
public async Task Hangman([Remainder]string type = "All")
|
||||
{
|
||||
var hm = new HangmanGame(Context.Channel, type);
|
||||
|
||||
@ -48,7 +48,14 @@ namespace NadekoBot.Modules.Games
|
||||
HangmanGame throwaway;
|
||||
HangmanGames.TryRemove(g.GameChannel.Id, out throwaway);
|
||||
};
|
||||
hm.Start();
|
||||
try
|
||||
{
|
||||
hm.Start();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
try { await Context.Channel.SendErrorAsync($"Starting errored: {ex.Message}").ConfigureAwait(false); } catch { }
|
||||
return;
|
||||
}
|
||||
|
||||
await Context.Channel.SendConfirmAsync("Hangman game started", hm.ScrambledWord + "\n" + hm.GetHangman() + "\n" + hm.ScrambledWord);
|
||||
}
|
||||
|
@ -94,7 +94,8 @@ namespace NadekoBot.Modules.Games
|
||||
lastGenerations.AddOrUpdate(channel.Id, DateTime.Now, (id, old) => DateTime.Now);
|
||||
|
||||
var sent = await channel.SendFileAsync(
|
||||
GetRandomCurrencyImagePath(),
|
||||
File.Open(GetRandomCurrencyImagePath(), FileMode.OpenOrCreate),
|
||||
"RandomFlower.jpg",
|
||||
$"❗ 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; });
|
||||
@ -104,7 +105,7 @@ namespace NadekoBot.Modules.Games
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
#if !GLOBAL_NADEKO
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task Pick()
|
||||
@ -163,11 +164,10 @@ namespace NadekoBot.Modules.Games
|
||||
}
|
||||
else
|
||||
{
|
||||
msg = await Context.Channel.SendFileAsync(file, msgToSend).ConfigureAwait(false);
|
||||
msg = await Context.Channel.SendFileAsync(File.Open(file, FileMode.OpenOrCreate), "plant.jpg", msgToSend).ConfigureAwait(false);
|
||||
}
|
||||
plantedFlowers.AddOrUpdate(Context.Channel.Id, new List<IUserMessage>() { msg }, (id, old) => { old.Add(msg); return old; });
|
||||
}
|
||||
#endif
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
|
@ -7,6 +7,7 @@ using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -17,7 +18,7 @@ namespace NadekoBot.Modules.Games
|
||||
[Group]
|
||||
public class PollCommands : ModuleBase
|
||||
{
|
||||
public static ConcurrentDictionary<IGuild, Poll> ActivePolls = new ConcurrentDictionary<IGuild, Poll>();
|
||||
public static ConcurrentDictionary<ulong, Poll> ActivePolls = new ConcurrentDictionary<ulong, Poll>();
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
@ -31,6 +32,18 @@ namespace NadekoBot.Modules.Games
|
||||
public Task PublicPoll([Remainder] string arg = null)
|
||||
=> InternalStartPoll(arg, isPublic: true);
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task PollStats()
|
||||
{
|
||||
Games.Poll poll;
|
||||
if (!ActivePolls.TryGetValue(Context.Guild.Id, out poll))
|
||||
return;
|
||||
|
||||
await Context.Channel.EmbedAsync(poll.GetStats("Current Poll Results"));
|
||||
}
|
||||
|
||||
private async Task InternalStartPoll(string arg, bool isPublic = false)
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
@ -44,7 +57,7 @@ namespace NadekoBot.Modules.Games
|
||||
return;
|
||||
|
||||
var poll = new Poll(Context.Message, data[0], data.Skip(1), isPublic: isPublic);
|
||||
if (ActivePolls.TryAdd(channel.Guild, poll))
|
||||
if (ActivePolls.TryAdd(channel.Guild.Id, poll))
|
||||
{
|
||||
await poll.StartPoll().ConfigureAwait(false);
|
||||
}
|
||||
@ -60,7 +73,7 @@ namespace NadekoBot.Modules.Games
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
|
||||
Poll poll;
|
||||
ActivePolls.TryRemove(channel.Guild, out poll);
|
||||
ActivePolls.TryRemove(channel.Guild.Id, out poll);
|
||||
await poll.StopPoll().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
@ -69,20 +82,55 @@ namespace NadekoBot.Modules.Games
|
||||
{
|
||||
private readonly IUserMessage originalMessage;
|
||||
private readonly IGuild guild;
|
||||
private readonly string[] answers;
|
||||
private string[] Answers { get; }
|
||||
private ConcurrentDictionary<ulong, int> participants = new ConcurrentDictionary<ulong, int>();
|
||||
private readonly string question;
|
||||
private DateTime started;
|
||||
private CancellationTokenSource pollCancellationSource = new CancellationTokenSource();
|
||||
private readonly bool isPublic;
|
||||
public bool IsPublic { get; }
|
||||
|
||||
public Poll(IUserMessage umsg, string question, IEnumerable<string> enumerable, bool isPublic = false)
|
||||
{
|
||||
this.originalMessage = umsg;
|
||||
this.guild = ((ITextChannel)umsg.Channel).Guild;
|
||||
this.question = question;
|
||||
this.answers = enumerable as string[] ?? enumerable.ToArray();
|
||||
this.isPublic = isPublic;
|
||||
this.Answers = enumerable as string[] ?? enumerable.ToArray();
|
||||
this.IsPublic = isPublic;
|
||||
}
|
||||
|
||||
public EmbedBuilder GetStats(string title)
|
||||
{
|
||||
var results = participants.GroupBy(kvp => kvp.Value)
|
||||
.ToDictionary(x => x.Key, x => x.Sum(kvp => 1))
|
||||
.OrderByDescending(kvp => kvp.Value)
|
||||
.ToArray();
|
||||
|
||||
var eb = new EmbedBuilder().WithTitle(title);
|
||||
|
||||
var sb = new StringBuilder()
|
||||
.AppendLine(Format.Bold(question))
|
||||
.AppendLine();
|
||||
|
||||
var totalVotesCast = 0;
|
||||
if (results.Length == 0)
|
||||
{
|
||||
sb.AppendLine("No votes cast.");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < results.Length; i++)
|
||||
{
|
||||
var result = results[i];
|
||||
sb.AppendLine($"`{i + 1}.` {Format.Bold(Answers[result.Key - 1])} with {Format.Bold(result.Value.ToString())} votes.");
|
||||
totalVotesCast += result.Value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
eb.WithDescription(sb.ToString())
|
||||
.WithFooter(efb => efb.WithText(totalVotesCast + " total votes cast."));
|
||||
|
||||
return eb;
|
||||
}
|
||||
|
||||
public async Task StartPoll()
|
||||
@ -91,8 +139,8 @@ namespace NadekoBot.Modules.Games
|
||||
NadekoBot.Client.MessageReceived += Vote;
|
||||
var msgToSend = $"📃**{originalMessage.Author.Username}** has created a poll which requires your attention:\n\n**{question}**\n";
|
||||
var num = 1;
|
||||
msgToSend = answers.Aggregate(msgToSend, (current, answ) => current + $"`{num++}.` **{answ}**\n");
|
||||
if (!isPublic)
|
||||
msgToSend = Answers.Aggregate(msgToSend, (current, answ) => current + $"`{num++}.` **{answ}**\n");
|
||||
if (!IsPublic)
|
||||
msgToSend += "\n**Private Message me with the corresponding number of the answer.**";
|
||||
else
|
||||
msgToSend += "\n**Send a Message here with the corresponding number of the answer.**";
|
||||
@ -102,30 +150,7 @@ namespace NadekoBot.Modules.Games
|
||||
public async Task StopPoll()
|
||||
{
|
||||
NadekoBot.Client.MessageReceived -= Vote;
|
||||
try
|
||||
{
|
||||
var results = participants.GroupBy(kvp => kvp.Value)
|
||||
.ToDictionary(x => x.Key, x => x.Sum(kvp => 1))
|
||||
.OrderByDescending(kvp => kvp.Value);
|
||||
|
||||
var totalVotesCast = results.Sum(kvp => kvp.Value);
|
||||
if (totalVotesCast == 0)
|
||||
{
|
||||
await originalMessage.Channel.SendMessageAsync("📄 **No votes have been cast.**").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
var closeMessage = $"--------------**POLL CLOSED**--------------\n" +
|
||||
$"📄 , here are the results:\n";
|
||||
closeMessage = results.Aggregate(closeMessage, (current, kvp) => current + $"`{kvp.Key}.` **[{answers[kvp.Key - 1]}]**" +
|
||||
$" has {kvp.Value} votes." +
|
||||
$"({kvp.Value * 1.0f / totalVotesCast * 100}%)\n");
|
||||
|
||||
await originalMessage.Channel.SendConfirmAsync($"📄 **Total votes cast**: {totalVotesCast}\n{closeMessage}").ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Error in poll game {ex}");
|
||||
}
|
||||
await originalMessage.Channel.EmbedAsync(GetStats("POLL CLOSED")).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async void Vote(SocketMessage imsg)
|
||||
@ -141,11 +166,11 @@ namespace NadekoBot.Modules.Games
|
||||
int vote;
|
||||
if (!int.TryParse(imsg.Content, out vote))
|
||||
return;
|
||||
if (vote < 1 || vote > answers.Length)
|
||||
if (vote < 1 || vote > Answers.Length)
|
||||
return;
|
||||
|
||||
IMessageChannel ch;
|
||||
if (isPublic)
|
||||
if (IsPublic)
|
||||
{
|
||||
//if public, channel must be the same the poll started in
|
||||
if (originalMessage.Channel.Id != imsg.Channel.Id)
|
||||
@ -167,7 +192,7 @@ namespace NadekoBot.Modules.Games
|
||||
//user can vote only once
|
||||
if (participants.TryAdd(msg.Author.Id, vote))
|
||||
{
|
||||
if (!isPublic)
|
||||
if (!IsPublic)
|
||||
{
|
||||
await ch.SendConfirmAsync($"Thanks for voting **{msg.Author.Username}**.").ConfigureAwait(false);
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ namespace NadekoBot.Modules.NSFW
|
||||
var link = await provider.ConfigureAwait(false);
|
||||
if (string.IsNullOrWhiteSpace(link))
|
||||
{
|
||||
if (noError)
|
||||
if (!noError)
|
||||
await channel.SendErrorAsync("No results found.").ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
|
@ -23,13 +23,18 @@ namespace NadekoBot.Modules.Permissions
|
||||
[Group]
|
||||
public class BlacklistCommands : ModuleBase
|
||||
{
|
||||
public static ConcurrentHashSet<BlacklistItem> BlacklistedItems { get; set; } = new ConcurrentHashSet<BlacklistItem>();
|
||||
public static ConcurrentHashSet<ulong> BlacklistedUsers { get; set; } = new ConcurrentHashSet<ulong>();
|
||||
public static ConcurrentHashSet<ulong> BlacklistedGuilds { get; set; } = new ConcurrentHashSet<ulong>();
|
||||
public static ConcurrentHashSet<ulong> BlacklistedChannels { get; set; } = new ConcurrentHashSet<ulong>();
|
||||
|
||||
static BlacklistCommands()
|
||||
{
|
||||
using (var uow = DbHandler.UnitOfWork())
|
||||
{
|
||||
BlacklistedItems = new ConcurrentHashSet<BlacklistItem>(uow.BotConfig.GetOrCreate().Blacklist);
|
||||
var blacklist = uow.BotConfig.GetOrCreate().Blacklist;
|
||||
BlacklistedUsers = new ConcurrentHashSet<ulong>(blacklist.Where(bi => bi.Type == BlacklistType.User).Select(c => c.ItemId));
|
||||
BlacklistedGuilds = new ConcurrentHashSet<ulong>(blacklist.Where(bi => bi.Type == BlacklistType.Server).Select(c => c.ItemId));
|
||||
BlacklistedChannels = new ConcurrentHashSet<ulong>(blacklist.Where(bi => bi.Type == BlacklistType.Channel).Select(c => c.ItemId));
|
||||
}
|
||||
}
|
||||
|
||||
@ -66,12 +71,34 @@ namespace NadekoBot.Modules.Permissions
|
||||
{
|
||||
var item = new BlacklistItem { ItemId = id, Type = type };
|
||||
uow.BotConfig.GetOrCreate().Blacklist.Add(item);
|
||||
BlacklistedItems.Add(item);
|
||||
if (type == BlacklistType.Server)
|
||||
{
|
||||
BlacklistedGuilds.Add(id);
|
||||
}
|
||||
else if (type == BlacklistType.Channel)
|
||||
{
|
||||
BlacklistedChannels.Add(id);
|
||||
}
|
||||
else if (type == BlacklistType.User)
|
||||
{
|
||||
BlacklistedUsers.Add(id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
uow.BotConfig.GetOrCreate().Blacklist.RemoveWhere(bi => bi.ItemId == id && bi.Type == type);
|
||||
BlacklistedItems.RemoveWhere(bi => bi.ItemId == id && bi.Type == type);
|
||||
if (type == BlacklistType.Server)
|
||||
{
|
||||
BlacklistedGuilds.TryRemove(id);
|
||||
}
|
||||
else if (type == BlacklistType.Channel)
|
||||
{
|
||||
BlacklistedChannels.TryRemove(id);
|
||||
}
|
||||
else if (type == BlacklistType.User)
|
||||
{
|
||||
BlacklistedUsers.TryRemove(id);
|
||||
}
|
||||
}
|
||||
await uow.CompleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
@ -23,8 +23,8 @@ namespace NadekoBot.Modules.Searches.Commands.Models
|
||||
public class Main
|
||||
{
|
||||
public double temp { get; set; }
|
||||
public int pressure { get; set; }
|
||||
public int humidity { get; set; }
|
||||
public float pressure { get; set; }
|
||||
public float humidity { get; set; }
|
||||
public double temp_min { get; set; }
|
||||
public double temp_max { get; set; }
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ namespace NadekoBot.Modules.Utility
|
||||
.AddField(fb => fb.WithName("**Voice Channels**").WithValue(voicechn.ToString()).WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Created At**").WithValue($"{createdAt.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Region**").WithValue(guild.VoiceRegionId.ToString()).WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Roles**").WithValue(guild.Roles.Count().ToString()).WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Roles**").WithValue((guild.Roles.Count - 1).ToString()).WithIsInline(true))
|
||||
.WithImageUrl(guild.IconUrl)
|
||||
.WithColor(NadekoBot.OkColor);
|
||||
if (guild.Emojis.Count() > 0)
|
||||
@ -92,8 +92,7 @@ namespace NadekoBot.Modules.Utility
|
||||
embed.AddField(fb => fb.WithName("**ID**").WithValue(user.Id.ToString()).WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Joined Server**").WithValue($"{user.JoinedAt?.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Joined Discord**").WithValue($"{user.CreatedAt.ToString("dd.MM.yyyy HH:mm")}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Current Game**").WithValue($"{(user.Game?.Name == null ? "-" : user.Game.Value.Name)}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Roles**").WithValue($"**({user.RoleIds.Count})** - {string.Join(", ", user.GetRoles().Select(r => r.Name)).SanitizeMentions()}").WithIsInline(true))
|
||||
.AddField(fb => fb.WithName("**Roles**").WithValue($"**({user.RoleIds.Count})** - {string.Join(", ", user.GetRoles().Where(r => r.Id != r.Guild.EveryoneRole.Id).Select(r => r.Name)).SanitizeMentions()}").WithIsInline(true))
|
||||
.WithThumbnailUrl(user.AvatarUrl)
|
||||
.WithColor(NadekoBot.OkColor);
|
||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||
|
@ -240,15 +240,27 @@ namespace NadekoBot.Modules.Utility
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
public async Task ChannelTopic()
|
||||
public async Task ChannelTopic([Remainder]ITextChannel channel = null)
|
||||
{
|
||||
var channel = (ITextChannel)Context.Channel;
|
||||
if (channel == null)
|
||||
channel = (ITextChannel)Context.Channel;
|
||||
|
||||
var topic = channel.Topic;
|
||||
if (string.IsNullOrWhiteSpace(topic))
|
||||
await channel.SendErrorAsync("No topic set.");
|
||||
await channel.SendErrorAsync("No topic set.").ConfigureAwait(false);
|
||||
else
|
||||
await channel.SendConfirmAsync("Channel topic", topic);
|
||||
await channel.SendConfirmAsync("Channel topic", topic).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
[RequireBotPermission(ChannelPermission.CreateInstantInvite)]
|
||||
[RequireUserPermission(ChannelPermission.CreateInstantInvite)]
|
||||
public async Task CreateInvite()
|
||||
{
|
||||
var invite = await ((ITextChannel)Context.Channel).CreateInviteAsync(0, null, isUnique: true);
|
||||
|
||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} https://discord.gg/{invite.Code}");
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
@ -269,8 +281,10 @@ namespace NadekoBot.Modules.Utility
|
||||
.AddField(efb => efb.WithName(Format.Bold("Memory")).WithValue($"{stats.Heap} MB").WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(Format.Bold("Owner ID(s)")).WithValue(stats.OwnerIds).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(Format.Bold("Uptime")).WithValue(stats.GetUptimeString("\n")).WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(Format.Bold("Presence")).WithValue($"{NadekoBot.Client.GetGuilds().Count} Servers\n{stats.TextChannels} Text Channels\n{stats.VoiceChannels} Voice Channels").WithIsInline(true))
|
||||
.AddField(efb => efb.WithName(Format.Bold("Presence")).WithValue($"{NadekoBot.Client.GetGuildsCount()} Servers\n{stats.TextChannels} Text Channels\n{stats.VoiceChannels} Voice Channels").WithIsInline(true))
|
||||
#if !GLOBAL_NADEKO
|
||||
.WithFooter(efb => efb.WithText($"Playing {Music.Music.MusicPlayers.Where(mp => mp.Value.CurrentSong != null).Count()} songs, {Music.Music.MusicPlayers.Sum(mp => mp.Value.Playlist.Count)} queued."))
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
@ -298,7 +312,7 @@ namespace NadekoBot.Modules.Utility
|
||||
if (page < 0)
|
||||
return;
|
||||
|
||||
var guilds = NadekoBot.Client.GetGuilds().OrderBy(g => g.Name).Skip((page - 1) * 15).Take(15);
|
||||
var guilds = await Task.Run(() => NadekoBot.Client.GetGuilds().OrderBy(g => g.Name).Skip((page - 1) * 15).Take(15)).ConfigureAwait(false);
|
||||
|
||||
if (!guilds.Any())
|
||||
{
|
||||
|
@ -91,7 +91,9 @@ namespace NadekoBot
|
||||
//connect
|
||||
await Client.LoginAsync(TokenType.Bot, Credentials.Token).ConfigureAwait(false);
|
||||
await Client.ConnectAsync().ConfigureAwait(false);
|
||||
//await Client.DownloadAllUsersAsync().ConfigureAwait(false);
|
||||
#if !GLOBAL_NADEKO
|
||||
await Client.DownloadAllUsersAsync().ConfigureAwait(false);
|
||||
#endif
|
||||
|
||||
_log.Info("Connected");
|
||||
|
||||
|
54
src/NadekoBot/Resources/CommandStrings.Designer.cs
generated
54
src/NadekoBot/Resources/CommandStrings.Designer.cs
generated
@ -1841,6 +1841,33 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to createinvite crinv.
|
||||
/// </summary>
|
||||
public static string createinvite_cmd {
|
||||
get {
|
||||
return ResourceManager.GetString("createinvite_cmd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Creates a new invite which has infinite max uses and never expires..
|
||||
/// </summary>
|
||||
public static string createinvite_desc {
|
||||
get {
|
||||
return ResourceManager.GetString("createinvite_desc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}crinv`.
|
||||
/// </summary>
|
||||
public static string createinvite_usage {
|
||||
get {
|
||||
return ResourceManager.GetString("createinvite_usage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to createrole cr.
|
||||
/// </summary>
|
||||
@ -5135,6 +5162,33 @@ namespace NadekoBot.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to pollstats.
|
||||
/// </summary>
|
||||
public static string pollstats_cmd {
|
||||
get {
|
||||
return ResourceManager.GetString("pollstats_cmd", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Shows the poll results without stopping the poll on this server..
|
||||
/// </summary>
|
||||
public static string pollstats_desc {
|
||||
get {
|
||||
return ResourceManager.GetString("pollstats_desc", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to `{0}pollstats`.
|
||||
/// </summary>
|
||||
public static string pollstats_usage {
|
||||
get {
|
||||
return ResourceManager.GetString("pollstats_usage", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to prune clr.
|
||||
/// </summary>
|
||||
|
@ -2871,4 +2871,22 @@
|
||||
<data name="rotaterolecolor_usage" xml:space="preserve">
|
||||
<value>`{0}rrc 60 MyLsdRole #ff0000 #00ff00 #0000ff` or `{0}rrc 0 MyLsdRole`</value>
|
||||
</data>
|
||||
<data name="createinvite_cmd" xml:space="preserve">
|
||||
<value>createinvite crinv</value>
|
||||
</data>
|
||||
<data name="createinvite_desc" xml:space="preserve">
|
||||
<value>Creates a new invite which has infinite max uses and never expires.</value>
|
||||
</data>
|
||||
<data name="createinvite_usage" xml:space="preserve">
|
||||
<value>`{0}crinv`</value>
|
||||
</data>
|
||||
<data name="pollstats_cmd" xml:space="preserve">
|
||||
<value>pollstats</value>
|
||||
</data>
|
||||
<data name="pollstats_desc" xml:space="preserve">
|
||||
<value>Shows the poll results without stopping the poll on this server.</value>
|
||||
</data>
|
||||
<data name="pollstats_usage" xml:space="preserve">
|
||||
<value>`{0}pollstats`</value>
|
||||
</data>
|
||||
</root>
|
@ -29,10 +29,16 @@ namespace Services.CleverBotApi
|
||||
|
||||
public static ChatterBot Create(ChatterBotType type, object arg)
|
||||
{
|
||||
#if GLOBAL_NADEKO
|
||||
var url = "http://www.cleverbot.com/webservicemin?uc=321&botapi=nadekobot";
|
||||
#else
|
||||
var url = "http://www.cleverbot.com/webservicemin?uc=321";
|
||||
#endif
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ChatterBotType.CLEVERBOT:
|
||||
return new Cleverbot("http://www.cleverbot.com/", "http://www.cleverbot.com/webservicemin?uc=321", 26);
|
||||
return new Cleverbot("http://www.cleverbot.com/", url, 26);
|
||||
case ChatterBotType.JABBERWACKY:
|
||||
return new Cleverbot("http://jabberwacky.com", "http://jabberwacky.com/webservicemin", 20);
|
||||
case ChatterBotType.PANDORABOTS:
|
||||
|
@ -46,7 +46,7 @@ namespace Services.CleverBotApi
|
||||
private readonly int endIndex;
|
||||
private readonly string url;
|
||||
private readonly IDictionary<string, string> vars;
|
||||
private readonly CookieCollection cookies;
|
||||
private readonly CookieCollection cookies;
|
||||
|
||||
public CleverbotSession(string baseUrl, string url, int endIndex)
|
||||
{
|
||||
@ -60,7 +60,7 @@ namespace Services.CleverBotApi
|
||||
//vars["fno"] = "0";
|
||||
//vars["sub"] = "Say";
|
||||
//vars["cleanslate"] = "false";
|
||||
cookies = Utils.GetCookies(baseUrl);
|
||||
cookies = Utils.GetCookies(baseUrl);
|
||||
}
|
||||
|
||||
public async Task<ChatterBotThought> Think(ChatterBotThought thought)
|
||||
|
@ -17,6 +17,8 @@ using static NadekoBot.Modules.Administration.Administration;
|
||||
using NadekoBot.Modules.CustomReactions;
|
||||
using NadekoBot.Modules.Games;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
using NadekoBot.DataStructures;
|
||||
|
||||
namespace NadekoBot.Services
|
||||
{
|
||||
@ -28,6 +30,8 @@ namespace NadekoBot.Services
|
||||
}
|
||||
public class CommandHandler
|
||||
{
|
||||
public const int GlobalCommandsCooldown = 1500;
|
||||
|
||||
private ShardedDiscordClient _client;
|
||||
private CommandService _commandService;
|
||||
private Logger _log;
|
||||
@ -39,11 +43,19 @@ namespace NadekoBot.Services
|
||||
//userid/msg count
|
||||
public ConcurrentDictionary<ulong, uint> UserMessagesSent { get; } = new ConcurrentDictionary<ulong, uint>();
|
||||
|
||||
public ConcurrentHashSet<ulong> UsersOnShortCooldown { get; } = new ConcurrentHashSet<ulong>();
|
||||
private Timer clearUsersOnShortCooldown { get; }
|
||||
|
||||
public CommandHandler(ShardedDiscordClient client, CommandService commandService)
|
||||
{
|
||||
_client = client;
|
||||
_commandService = commandService;
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
clearUsersOnShortCooldown = new Timer((_) =>
|
||||
{
|
||||
UsersOnShortCooldown.Clear();
|
||||
}, null, GlobalCommandsCooldown, GlobalCommandsCooldown);
|
||||
}
|
||||
public async Task StartHandling()
|
||||
{
|
||||
@ -62,162 +74,202 @@ namespace NadekoBot.Services
|
||||
_client.MessageReceived += MessageReceivedHandler;
|
||||
}
|
||||
|
||||
private async void MessageReceivedHandler(SocketMessage msg)
|
||||
private async Task<bool> TryRunCleverbot(SocketUserMessage usrMsg, IGuild guild)
|
||||
{
|
||||
if (guild == null)
|
||||
return false;
|
||||
try
|
||||
{
|
||||
var usrMsg = msg as SocketUserMessage;
|
||||
if (usrMsg == null)
|
||||
return;
|
||||
|
||||
//if (!usrMsg.IsAuthor())
|
||||
// UserMessagesSent.AddOrUpdate(usrMsg.Author.Id, 1, (key, old) => ++old);
|
||||
|
||||
if (msg.Author.IsBot || !NadekoBot.Ready) //no bots
|
||||
return;
|
||||
|
||||
var guild = (msg.Channel as SocketTextChannel)?.Guild;
|
||||
|
||||
if (guild != null && guild.OwnerId != msg.Author.Id)
|
||||
var cleverbotExecuted = await Games.CleverBotCommands.TryAsk(usrMsg).ConfigureAwait(false);
|
||||
if (cleverbotExecuted)
|
||||
{
|
||||
//todo split checks into their own modules
|
||||
if (Permissions.FilterCommands.InviteFilteringChannels.Contains(msg.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 " + msg.Channel.Id, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var filteredWords = Permissions.FilterCommands.FilteredWordsForChannel(msg.Channel.Id, guild.Id).Concat(Permissions.FilterCommands.FilteredWordsForServer(guild.Id));
|
||||
var wordsInMessage = usrMsg.Content.ToLowerInvariant().Split(' ');
|
||||
if (filteredWords.Any(w => wordsInMessage.Contains(w)))
|
||||
{
|
||||
try
|
||||
{
|
||||
await usrMsg.DeleteAsync().ConfigureAwait(false);
|
||||
return;
|
||||
}
|
||||
catch (HttpException ex)
|
||||
{
|
||||
_log.Warn("I do not have permission to filter words in channel with id " + msg.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 == msg.Author.Id))) != null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var cleverbotExecuted = await Games.CleverBotCommands.TryAsk(usrMsg);
|
||||
if (cleverbotExecuted)
|
||||
{
|
||||
_log.Info($@"CleverBot Executed
|
||||
_log.Info($@"CleverBot Executed
|
||||
Server: {guild.Name} [{guild.Id}]
|
||||
Channel: {usrMsg.Channel?.Name} [{usrMsg.Channel?.Id}]
|
||||
UserId: {usrMsg.Author} [{usrMsg.Author.Id}]
|
||||
Message: {usrMsg.Content}");
|
||||
return;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex, "Error in cleverbot"); }
|
||||
}
|
||||
catch (Exception ex) { _log.Warn(ex, "Error in cleverbot"); }
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// maybe this message is a custom reaction
|
||||
var crExecuted = await CustomReactions.TryExecuteCustomReaction(usrMsg).ConfigureAwait(false);
|
||||
private bool IsBlacklisted(IGuild guild, SocketUserMessage usrMsg) =>
|
||||
(guild != null && BlacklistCommands.BlacklistedGuilds.Contains(guild.Id)) ||
|
||||
BlacklistCommands.BlacklistedChannels.Contains(usrMsg.Channel.Id) ||
|
||||
BlacklistCommands.BlacklistedUsers.Contains(usrMsg.Author.Id);
|
||||
|
||||
//if it was, don't execute the command
|
||||
if (crExecuted)
|
||||
return;
|
||||
}
|
||||
catch { }
|
||||
|
||||
string messageContent = usrMsg.Content;
|
||||
private async Task LogSuccessfulExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, Stopwatch sw)
|
||||
{
|
||||
await CommandExecuted(usrMsg, exec.CommandInfo).ConfigureAwait(false);
|
||||
_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);
|
||||
}
|
||||
|
||||
var sw = new Stopwatch();
|
||||
sw.Start();
|
||||
var exec = await ExecuteCommand(new CommandContext(_client.MainClient, usrMsg), messageContent, DependencyMap.Empty, MultiMatchHandling.Best);
|
||||
var command = exec.CommandInfo;
|
||||
var permCache = exec.PermissionCache;
|
||||
var result = exec.Result;
|
||||
sw.Stop();
|
||||
var channel = (msg.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}",
|
||||
msg.Author + " [" + msg.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" +
|
||||
private void LogErroredExecution(SocketUserMessage usrMsg, ExecuteCommandResult exec, SocketTextChannel channel, Stopwatch sw)
|
||||
{
|
||||
_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}",
|
||||
msg.Author + " [" + msg.Author.Id + "]", // {0}
|
||||
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}
|
||||
exec.Result.ErrorReason, // {4}
|
||||
sw.Elapsed.TotalSeconds // {5}
|
||||
);
|
||||
if (guild != null && command != null && result.Error == CommandError.Exception)
|
||||
}
|
||||
|
||||
private async Task<bool> InviteFiltered(IGuild guild, SocketUserMessage usrMsg)
|
||||
{
|
||||
if ((Permissions.FilterCommands.InviteFilteringChannels.Contains(usrMsg.Channel.Id) ||
|
||||
Permissions.FilterCommands.InviteFilteringServers.Contains(guild.Id)) &&
|
||||
usrMsg.Content.IsDiscordInvite())
|
||||
{
|
||||
try
|
||||
{
|
||||
await usrMsg.DeleteAsync().ConfigureAwait(false);
|
||||
return true;
|
||||
}
|
||||
catch (HttpException ex)
|
||||
{
|
||||
_log.Warn("I do not have permission to filter invites in channel with id " + usrMsg.Channel.Id, ex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task<bool> WordFiltered(IGuild guild, SocketUserMessage usrMsg)
|
||||
{
|
||||
var filteredChannelWords = Permissions.FilterCommands.FilteredWordsForChannel(usrMsg.Channel.Id, guild.Id);
|
||||
var filteredServerWords = Permissions.FilterCommands.FilteredWordsForServer(guild.Id);
|
||||
var wordsInMessage = usrMsg.Content.ToLowerInvariant().Split(' ');
|
||||
if (filteredChannelWords.Count != 0 || filteredServerWords.Count != 0)
|
||||
{
|
||||
foreach (var word in wordsInMessage)
|
||||
{
|
||||
if (filteredChannelWords.Contains(word) ||
|
||||
filteredServerWords.Contains(word))
|
||||
{
|
||||
if (permCache != null && permCache.Verbose)
|
||||
try { await msg.Channel.SendMessageAsync("⚠️ " + result.ErrorReason).ConfigureAwait(false); } catch { }
|
||||
try
|
||||
{
|
||||
await usrMsg.DeleteAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch (HttpException ex)
|
||||
{
|
||||
_log.Warn("I do not have permission to filter words in channel with id " + usrMsg.Channel.Id, ex);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private async void MessageReceivedHandler(SocketMessage msg)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (msg.Author.IsBot || !NadekoBot.Ready) //no bots, wait until bot connected and initialized
|
||||
return;
|
||||
|
||||
var usrMsg = msg as SocketUserMessage;
|
||||
if (usrMsg == null) //has to be an user message, not system/other messages.
|
||||
return;
|
||||
|
||||
// track how many messagges each user is sending
|
||||
UserMessagesSent.AddOrUpdate(usrMsg.Author.Id, 1, (key, old) => ++old);
|
||||
|
||||
// Bot will ignore commands which are ran more often than what specified by
|
||||
// GlobalCommandsCooldown constant (miliseconds)
|
||||
if (!UsersOnShortCooldown.Add(usrMsg.Author.Id))
|
||||
return;
|
||||
|
||||
var channel = msg.Channel as SocketTextChannel;
|
||||
var guild = channel?.Guild;
|
||||
|
||||
if (guild != null && guild.OwnerId != msg.Author.Id)
|
||||
{
|
||||
if (await InviteFiltered(guild, usrMsg).ConfigureAwait(false))
|
||||
return;
|
||||
|
||||
if (await WordFiltered(guild, usrMsg).ConfigureAwait(false))
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsBlacklisted(guild, usrMsg))
|
||||
return;
|
||||
|
||||
var cleverBotRan = await TryRunCleverbot(usrMsg, guild).ConfigureAwait(false);
|
||||
if (cleverBotRan)
|
||||
return;
|
||||
|
||||
// maybe this message is a custom reaction
|
||||
var crExecuted = await CustomReactions.TryExecuteCustomReaction(usrMsg).ConfigureAwait(false);
|
||||
if (crExecuted) //if it was, don't execute the command
|
||||
return;
|
||||
|
||||
string messageContent = usrMsg.Content;
|
||||
|
||||
// execute the command and measure the time it took
|
||||
var sw = Stopwatch.StartNew();
|
||||
var exec = await ExecuteCommand(new CommandContext(_client.MainClient, usrMsg), messageContent, DependencyMap.Empty, MultiMatchHandling.Best);
|
||||
sw.Stop();
|
||||
|
||||
if (exec.Result.IsSuccess)
|
||||
{
|
||||
await LogSuccessfulExecution(usrMsg, exec, channel, sw).ConfigureAwait(false);
|
||||
}
|
||||
else if (!exec.Result.IsSuccess && exec.Result.Error != CommandError.UnknownCommand)
|
||||
{
|
||||
LogErroredExecution(usrMsg, exec, channel, sw);
|
||||
if (guild != null && exec.CommandInfo != null && exec.Result.Error == CommandError.Exception)
|
||||
{
|
||||
if (exec.PermissionCache != null && exec.PermissionCache.Verbose)
|
||||
try { await msg.Channel.SendMessageAsync("⚠️ " + exec.Result.ErrorReason).ConfigureAwait(false); } catch { }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (msg.Channel is IPrivateChannel)
|
||||
{
|
||||
//rofl, gotta do this to prevent this message from occuring on polls
|
||||
// rofl, gotta do this to prevent dm help message being sent to
|
||||
// users who are voting on private polls (sending a number in a DM)
|
||||
int vote;
|
||||
if (int.TryParse(msg.Content, out vote)) return;
|
||||
|
||||
|
||||
await msg.Channel.SendMessageAsync(Help.DMHelpString).ConfigureAwait(false);
|
||||
|
||||
await DMForwardCommands.HandleDMForwarding(msg, ownerChannels);
|
||||
await DMForwardCommands.HandleDMForwarding(msg, ownerChannels).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex, "Error in CommandHandler");
|
||||
_log.Warn("Error in CommandHandler");
|
||||
_log.Warn(ex);
|
||||
if (ex.InnerException != null)
|
||||
_log.Warn(ex.InnerException, "Inner Exception of the error in CommandHandler");
|
||||
{
|
||||
_log.Warn("Inner Exception of the error in CommandHandler");
|
||||
_log.Warn(ex.InnerException);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public Task<ExecuteCommandResult> ExecuteCommandAsync(CommandContext context, int argPos, IDependencyMap dependencyMap = null, MultiMatchHandling multiMatchHandling = MultiMatchHandling.Exception)
|
||||
=> ExecuteCommand(context, context.Message.Content.Substring(argPos), dependencyMap, multiMatchHandling);
|
||||
|
||||
@ -312,19 +364,5 @@ namespace NadekoBot.Services
|
||||
|
||||
return new ExecuteCommandResult(null, null, SearchResult.FromError(CommandError.UnknownCommand, "This input does not match any overload."));
|
||||
}
|
||||
|
||||
public struct ExecuteCommandResult
|
||||
{
|
||||
public readonly CommandInfo CommandInfo;
|
||||
public readonly PermissionCache PermissionCache;
|
||||
public readonly IResult Result;
|
||||
|
||||
public ExecuteCommandResult(CommandInfo commandInfo, PermissionCache cache, IResult result)
|
||||
{
|
||||
this.CommandInfo = commandInfo;
|
||||
this.PermissionCache = cache;
|
||||
this.Result = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
66
src/NadekoBot/Services/Discord/SocketMessageEventWrapper.cs
Normal file
66
src/NadekoBot/Services/Discord/SocketMessageEventWrapper.cs
Normal file
@ -0,0 +1,66 @@
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Services.Discord
|
||||
{
|
||||
public class ReactionEventWrapper : IDisposable
|
||||
{
|
||||
public SocketMessage Message { get; }
|
||||
public event Action<SocketReaction> OnReactionAdded = delegate { };
|
||||
public event Action<SocketReaction> OnReactionRemoved = delegate { };
|
||||
public event Action OnReactionsCleared = delegate { };
|
||||
|
||||
public ReactionEventWrapper(SocketMessage msg)
|
||||
{
|
||||
if (msg == null)
|
||||
throw new ArgumentNullException(nameof(msg));
|
||||
Message = msg;
|
||||
|
||||
msg.Discord.ReactionAdded += Discord_ReactionAdded;
|
||||
msg.Discord.ReactionRemoved += Discord_ReactionRemoved;
|
||||
msg.Discord.ReactionsCleared += Discord_ReactionsCleared;
|
||||
}
|
||||
|
||||
private Task Discord_ReactionsCleared(ulong messageId, Optional<SocketUserMessage> reaction)
|
||||
{
|
||||
if (messageId == Message.Id)
|
||||
OnReactionsCleared?.Invoke();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task Discord_ReactionRemoved(ulong messageId, Optional<SocketUserMessage> arg2, SocketReaction reaction)
|
||||
{
|
||||
if (messageId == Message.Id)
|
||||
OnReactionRemoved?.Invoke(reaction);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private Task Discord_ReactionAdded(ulong messageId, Optional<SocketUserMessage> message, SocketReaction reaction)
|
||||
{
|
||||
if(messageId == Message.Id)
|
||||
OnReactionAdded?.Invoke(reaction);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public void UnsubAll()
|
||||
{
|
||||
Message.Discord.ReactionAdded -= Discord_ReactionAdded;
|
||||
Message.Discord.ReactionRemoved -= Discord_ReactionRemoved;
|
||||
Message.Discord.ReactionsCleared -= Discord_ReactionsCleared;
|
||||
}
|
||||
|
||||
private bool disposing = false;
|
||||
public void Dispose()
|
||||
{
|
||||
if (disposing)
|
||||
return;
|
||||
disposing = true;
|
||||
UnsubAll();
|
||||
}
|
||||
}
|
||||
}
|
@ -20,12 +20,15 @@ namespace NadekoBot.Services.Impl
|
||||
public string Library => "Discord.Net";
|
||||
public int MessageCounter { get; private set; } = 0;
|
||||
public int CommandsRan { get; private set; } = 0;
|
||||
public string Heap => Math.Round((double)GC.GetTotalMemory(false) / 1.MiB(), 2).ToString();
|
||||
public double MessagesPerSecond => MessageCounter / (double)GetUptime().TotalSeconds;
|
||||
public int TextChannels => client.GetGuilds().SelectMany(g => g.Channels.Where(c => c is ITextChannel)).Count();
|
||||
public int VoiceChannels => client.GetGuilds().SelectMany(g => g.Channels.Where(c => c is IVoiceChannel)).Count();
|
||||
public string Heap =>
|
||||
Math.Round((double)GC.GetTotalMemory(false) / 1.MiB(), 2).ToString();
|
||||
public double MessagesPerSecond => MessageCounter / GetUptime().TotalSeconds;
|
||||
private int _textChannels = 0;
|
||||
public int TextChannels => _textChannels;
|
||||
private int _voiceChannels = 0;
|
||||
public int VoiceChannels => _voiceChannels;
|
||||
public string OwnerIds => string.Join(", ", NadekoBot.Credentials.OwnerIds);
|
||||
|
||||
|
||||
Timer carbonitexTimer { get; }
|
||||
|
||||
public StatsService(ShardedDiscordClient client, CommandHandler cmdHandler)
|
||||
@ -39,17 +42,56 @@ namespace NadekoBot.Services.Impl
|
||||
|
||||
this.client.Disconnected += _ => Reset();
|
||||
|
||||
this.client.Connected += () =>
|
||||
{
|
||||
var guilds = this.client.GetGuilds();
|
||||
_textChannels = guilds.Sum(g => g.Channels.Where(cx => cx is ITextChannel).Count());
|
||||
_voiceChannels = guilds.Sum(g => g.Channels.Count) - _textChannels;
|
||||
};
|
||||
|
||||
this.client.ChannelCreated += (c) =>
|
||||
{
|
||||
if (c is ITextChannel)
|
||||
++_textChannels;
|
||||
else if (c is IVoiceChannel)
|
||||
++_voiceChannels;
|
||||
};
|
||||
|
||||
this.client.ChannelDestroyed += (c) =>
|
||||
{
|
||||
if (c is ITextChannel)
|
||||
--_textChannels;
|
||||
else if (c is IVoiceChannel)
|
||||
--_voiceChannels;
|
||||
};
|
||||
|
||||
this.client.JoinedGuild += (g) =>
|
||||
{
|
||||
var tc = g.Channels.Where(cx => cx is ITextChannel).Count();
|
||||
var vc = g.Channels.Count - tc;
|
||||
_textChannels += tc;
|
||||
_voiceChannels += vc;
|
||||
};
|
||||
|
||||
this.client.LeftGuild += (g) =>
|
||||
{
|
||||
var tc = g.Channels.Where(cx => cx is ITextChannel).Count();
|
||||
var vc = g.Channels.Count - tc;
|
||||
_textChannels -= tc;
|
||||
_voiceChannels -= vc;
|
||||
};
|
||||
|
||||
this.carbonitexTimer = new Timer(async (state) =>
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.CarbonKey))
|
||||
return;
|
||||
if (string.IsNullOrWhiteSpace(NadekoBot.Credentials.CarbonKey))
|
||||
return;
|
||||
try
|
||||
{
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
using (var content = new FormUrlEncodedContent(
|
||||
new Dictionary<string, string> {
|
||||
{ "servercount", this.client.GetGuilds().Count.ToString() },
|
||||
{ "servercount", this.client.GetGuildsCount().ToString() },
|
||||
{ "key", NadekoBot.Credentials.CarbonKey }}))
|
||||
{
|
||||
content.Headers.Clear();
|
||||
@ -71,7 +113,7 @@ Bot Version: [{BotVersion}]
|
||||
Bot ID: {curUser.Id}
|
||||
Owner ID(s): {OwnerIds}
|
||||
Uptime: {GetUptimeString()}
|
||||
Servers: {client.GetGuilds().Count} | TextChannels: {TextChannels} | VoiceChannels: {VoiceChannels}
|
||||
Servers: {client.GetGuildsCount()} | TextChannels: {TextChannels} | VoiceChannels: {VoiceChannels}
|
||||
Commands Ran this session: {CommandsRan}
|
||||
Messages: {MessageCounter} [{MessagesPerSecond:F2}/sec] Heap: [{Heap} MB]");
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ namespace NadekoBot
|
||||
public event Action<SocketMessage> MessageReceived = delegate { };
|
||||
public event Action<SocketGuildUser> UserLeft = delegate { };
|
||||
public event Action<SocketUser, SocketUser> UserUpdated = delegate { };
|
||||
public event Action<SocketGuildUser, SocketGuildUser> GuildUserUpdated = delegate { };
|
||||
public event Action<Optional<SocketMessage>, SocketMessage> MessageUpdated = delegate { };
|
||||
public event Action<ulong, Optional<SocketMessage>> MessageDeleted = delegate { };
|
||||
public event Action<SocketUser, SocketGuild> UserBanned = delegate { };
|
||||
@ -27,11 +28,18 @@ namespace NadekoBot
|
||||
public event Action<SocketChannel> ChannelCreated = delegate { };
|
||||
public event Action<SocketChannel> ChannelDestroyed = delegate { };
|
||||
public event Action<SocketChannel, SocketChannel> ChannelUpdated = delegate { };
|
||||
|
||||
public event Action<SocketGuild> JoinedGuild = delegate { };
|
||||
public event Action<SocketGuild> LeftGuild = delegate { };
|
||||
|
||||
public event Action<Exception> Disconnected = delegate { };
|
||||
public event Action Connected = delegate { };
|
||||
|
||||
private uint _connectedCount = 0;
|
||||
private uint _downloadedCount = 0;
|
||||
|
||||
private int _guildCount = 0;
|
||||
|
||||
private IReadOnlyList<DiscordSocketClient> Clients { get; }
|
||||
|
||||
public ShardedDiscordClient(DiscordSocketConfig discordSocketConfig)
|
||||
@ -54,6 +62,7 @@ namespace NadekoBot
|
||||
};
|
||||
client.UserLeft += arg1 => { UserLeft(arg1); return Task.CompletedTask; };
|
||||
client.UserUpdated += (arg1, gu2) => { UserUpdated(arg1, gu2); return Task.CompletedTask; };
|
||||
client.GuildMemberUpdated += (arg1, arg2) => { GuildUserUpdated(arg1, arg2); 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; };
|
||||
@ -63,9 +72,13 @@ namespace NadekoBot
|
||||
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; };
|
||||
client.JoinedGuild += (arg1) => { JoinedGuild(arg1); ++_guildCount; return Task.CompletedTask; };
|
||||
client.LeftGuild += (arg1) => { LeftGuild(arg1); --_guildCount; return Task.CompletedTask; };
|
||||
|
||||
_log.Info($"Shard #{i} initialized.");
|
||||
#if GLOBAL_NADEKO
|
||||
client.Log += Client_Log;
|
||||
#endif
|
||||
var j = i;
|
||||
client.Disconnected += (ex) =>
|
||||
{
|
||||
@ -91,11 +104,22 @@ namespace NadekoBot
|
||||
public SocketSelfUser CurrentUser() =>
|
||||
Clients[0].CurrentUser;
|
||||
|
||||
public IReadOnlyCollection<SocketGuild> GetGuilds() =>
|
||||
Clients.SelectMany(c => c.Guilds).ToList();
|
||||
public IEnumerable<SocketGuild> GetGuilds() =>
|
||||
Clients.SelectMany(c => c.Guilds);
|
||||
|
||||
public SocketGuild GetGuild(ulong id) =>
|
||||
Clients.Select(c => c.GetGuild(id)).FirstOrDefault(g => g != null);
|
||||
public int GetGuildsCount() =>
|
||||
_guildCount;
|
||||
|
||||
public SocketGuild GetGuild(ulong id)
|
||||
{
|
||||
foreach (var c in Clients)
|
||||
{
|
||||
var g = c.GetGuild(id);
|
||||
if (g != null)
|
||||
return g;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Task<IDMChannel> GetDMChannelAsync(ulong channelId) =>
|
||||
Clients[0].GetDMChannelAsync(channelId);
|
||||
@ -120,6 +144,7 @@ namespace NadekoBot
|
||||
await c.ConnectAsync().ConfigureAwait(false);
|
||||
sw.Stop();
|
||||
_log.Info($"Shard #{c.ShardId} connected after {sw.Elapsed.TotalSeconds:F2}s ({++_connectedCount}/{Clients.Count})");
|
||||
_guildCount += c.Guilds.Count;
|
||||
}
|
||||
catch
|
||||
{
|
||||
@ -132,6 +157,7 @@ namespace NadekoBot
|
||||
}
|
||||
}
|
||||
}
|
||||
Connected();
|
||||
}
|
||||
|
||||
internal Task DownloadAllUsersAsync() =>
|
||||
|
@ -1,6 +1,8 @@
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using ImageSharp;
|
||||
using NadekoBot.Services.Discord;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
@ -16,6 +18,13 @@ namespace NadekoBot.Extensions
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
public static ReactionEventWrapper OnReactionAdded(this SocketMessage msg, Action<SocketReaction> reactionAdded)
|
||||
{
|
||||
var wrap = new ReactionEventWrapper(msg);
|
||||
wrap.OnReactionAdded += reactionAdded;
|
||||
return wrap;
|
||||
}
|
||||
|
||||
public static void AddFakeHeaders(this HttpClient http)
|
||||
{
|
||||
http.DefaultRequestHeaders.Clear();
|
||||
|
Loading…
Reference in New Issue
Block a user