Merge pull request #5 from Kwoth/master

Updating fork
This commit is contained in:
miraai 2016-07-28 20:22:03 +02:00 committed by GitHub
commit 54bed4ecc9
40 changed files with 1233 additions and 630 deletions

3
.gitmodules vendored
View File

@ -1,3 +1,6 @@
[submodule "discord.net"]
path = discord.net
url = git://github.com/kwoth/discord.net.git
[submodule "ffmpeg-installer"]
path = ffmpeg-installer
url = https://github.com/kwoth/ffmpeg-installer

View File

@ -36,9 +36,7 @@ ________________________________________________________________________________
###### Setting up `ffmpeg` with installer:
1) Google Account
2) Soundcloud Account (if you want soundcloud support)
3) Download installer here: http://luxcaeli.de/owncloud/s/fIxSgh4Nde3Td6e/download
3) Download installer here: https://goo.gl/lQZnsH (pick the one for your system, either 32 or 64bit and then click 'download')
4) Run the installer
5) Follow these steps on how to setup API keys:

View File

@ -138,7 +138,7 @@ namespace NadekoBot.Extensions
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="list"></param>
public static void Shuffle<T>(this IList<T> list)
public static IList<T> Shuffle<T>(this IList<T> list)
{
// Thanks to @Joe4Evr for finding a bug in the old version of the shuffle
@ -160,6 +160,7 @@ namespace NadekoBot.Extensions
list[k] = list[n];
list[n] = value;
}
return list;
}
/// <summary>
@ -303,6 +304,15 @@ namespace NadekoBot.Extensions
public static int GiB(this int value) => value.MiB() * 1024;
public static int GB(this int value) => value.MB() * 1000;
public static ulong KiB(this ulong value) => value * 1024;
public static ulong KB(this ulong value) => value * 1000;
public static ulong MiB(this ulong value) => value.KiB() * 1024;
public static ulong MB(this ulong value) => value.KB() * 1000;
public static ulong GiB(this ulong value) => value.MiB() * 1024;
public static ulong GB(this ulong value) => value.MB() * 1000;
public static Stream ToStream(this Image img, System.Drawing.Imaging.ImageFormat format = null)
{
if (format == null)
@ -362,5 +372,7 @@ namespace NadekoBot.Extensions
return sw.BaseStream;
}
public static double UnixTimestamp(this DateTime dt) => dt.ToUniversalTime().Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
}
}

View File

@ -4,8 +4,10 @@ using NadekoBot.Extensions;
using NadekoBot.Modules.Administration.Commands;
using NadekoBot.Modules.Music;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
@ -41,7 +43,23 @@ namespace NadekoBot
var commandService = NadekoBot.Client.GetService<CommandService>();
statsStopwatch.Start();
commandService.CommandExecuted += StatsCollector_RanCommand;
commandService.CommandFinished += CommandService_CommandFinished;
commandService.CommandErrored += (s, e) =>
{
try
{
if (e.ErrorType == CommandErrorType.Exception)
File.AppendAllText("errors.txt", $@"Command: {e.Command}
{e.Exception}
-------------------------------------
");
}
catch {
Console.WriteLine("Command errored errorring");
}
};
Task.Run(StartCollecting);
@ -97,7 +115,7 @@ namespace NadekoBot
if (e.Channel.IsPrivate)
return;
if (e.Channel.Type == ChannelType.Text)
VoiceChannelsCount++;
TextChannelsCount--;
else if (e.Channel.Type == ChannelType.Voice)
VoiceChannelsCount--;
}
@ -106,6 +124,7 @@ namespace NadekoBot
carbonStatusTimer.Elapsed += async (s, e) => await SendUpdateToCarbon().ConfigureAwait(false);
carbonStatusTimer.Start();
}
HttpClient carbonClient = new HttpClient();
private async Task SendUpdateToCarbon()
{
@ -176,9 +195,11 @@ namespace NadekoBot
private async Task StartCollecting()
{
var statsSw = new Stopwatch();
while (true)
{
await Task.Delay(new TimeSpan(0, 30, 0)).ConfigureAwait(false);
statsSw.Start();
try
{
var onlineUsers = await Task.Run(() => NadekoBot.Client.Servers.Sum(x => x.Users.Count())).ConfigureAwait(false);
@ -195,6 +216,13 @@ namespace NadekoBot
ConnectedServers = connectedServers,
DateAdded = DateTime.Now
});
statsSw.Stop();
var clr = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Blue;
Console.WriteLine($"--------------\nCollecting stats finished in {statsSw.Elapsed.TotalSeconds}s\n-------------");
Console.ForegroundColor = clr;
statsSw.Reset();
}
catch
{
@ -204,9 +232,21 @@ namespace NadekoBot
}
}
private static ConcurrentDictionary<ulong, DateTime> commandTracker = new ConcurrentDictionary<ulong, DateTime>();
private void CommandService_CommandFinished(object sender, CommandEventArgs e)
{
DateTime dt;
if (!commandTracker.TryGetValue(e.Message.Id, out dt))
return;
Console.WriteLine($">>COMMAND ENDED after *{(DateTime.UtcNow - dt).TotalSeconds}s*\nCmd: {e.Command.Text}\nMsg: {e.Message.Text}\nUsr: {e.User.Name} [{e.User.Id}]\nSrvr: {e.Server?.Name ?? "PRIVATE"} [{e.Server?.Id}]\n-----");
}
private async void StatsCollector_RanCommand(object sender, CommandEventArgs e)
{
Console.WriteLine($">> Cmd: {e.Command.Text}\nMsg: {e.Message.Text}\nUsr: {e.User.Name} [{e.User.Id}]\nSrvr: {e.Server?.Name ?? "PRIVATE"} [{e.Server?.Id}]\n-----");
commandTracker.TryAdd(e.Message.Id, DateTime.UtcNow);
Console.WriteLine($">>COMMAND STARTED\nCmd: {e.Command.Text}\nMsg: {e.Message.Text}\nUsr: {e.User.Name} [{e.User.Id}]\nSrvr: {e.Server?.Name ?? "PRIVATE"} [{e.Server?.Id}]\n-----");
#if !NADEKO_RELEASE
await Task.Run(() =>
{
try
@ -230,6 +270,7 @@ namespace NadekoBot
Console.WriteLine(ex);
}
}).ConfigureAwait(false);
#endif
}
}
}

View File

@ -364,9 +364,7 @@ namespace NadekoBot.Classes
}
var httpResponse = (await httpWebRequest.GetResponseAsync().ConfigureAwait(false)) as HttpWebResponse;
if (httpResponse == null) return "HTTP_RESPONSE_ERROR";
var responseStream = httpResponse.GetResponseStream();
if (responseStream == null) return "RESPONSE_STREAM ERROR";
using (var streamReader = new StreamReader(responseStream))
{
var responseText = await streamReader.ReadToEndAsync().ConfigureAwait(false);
@ -375,6 +373,7 @@ namespace NadekoBot.Classes
}
catch (Exception ex)
{
Console.WriteLine("Shortening of this url failed: " + url);
Console.WriteLine(ex.ToString());
return url;
}

View File

@ -6,6 +6,8 @@ using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
namespace NadekoBot.Classes
{
@ -27,9 +29,12 @@ namespace NadekoBot.Classes
{
configs = JsonConvert
.DeserializeObject<ConcurrentDictionary<ulong, ServerSpecificConfig>>(
File.ReadAllText(filePath), new JsonSerializerSettings() {
Error = (s,e) => {
if (e.ErrorContext.Member.ToString() == "GenerateCurrencyChannels") {
File.ReadAllText(filePath), new JsonSerializerSettings()
{
Error = (s, e) =>
{
if (e.ErrorContext.Member.ToString() == "GenerateCurrencyChannels")
{
e.ErrorContext.Handled = true;
}
}
@ -52,14 +57,19 @@ namespace NadekoBot.Classes
public ServerSpecificConfig Of(ulong id) =>
configs.GetOrAdd(id, _ => new ServerSpecificConfig());
private readonly object saveLock = new object();
private readonly SemaphoreSlim saveLock = new SemaphoreSlim(1, 1);
public void Save()
public async Task Save()
{
lock (saveLock)
await saveLock.WaitAsync();
try
{
File.WriteAllText(filePath, JsonConvert.SerializeObject(configs, Formatting.Indented));
}
finally
{
saveLock.Release();
}
}
}
@ -245,7 +255,7 @@ namespace NadekoBot.Classes
LogserverIgnoreChannels = new ObservableCollection<ulong>();
}
public event PropertyChangedEventHandler PropertyChanged = delegate { SpecificConfigurations.Default.Save(); };
public event PropertyChangedEventHandler PropertyChanged = async delegate { await SpecificConfigurations.Default.Save().ConfigureAwait(false); };
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{

View File

@ -70,7 +70,7 @@ namespace NadekoBot.Modules.Administration
{
var conf = SpecificConfigurations.Default.Of(e.Server.Id);
conf.AutoDeleteMessagesOnCommand = !conf.AutoDeleteMessagesOnCommand;
Classes.JSONModels.ConfigHandler.SaveConfig();
await Classes.JSONModels.ConfigHandler.SaveConfig().ConfigureAwait(false);
if (conf.AutoDeleteMessagesOnCommand)
await e.Channel.SendMessage("❗`Now automatically deleting successfull command invokations.`");
else
@ -90,7 +90,7 @@ namespace NadekoBot.Modules.Administration
});
cgb.CreateCommand(Prefix + "setrole").Alias(Prefix + "sr")
.Description("Sets a role for a given user. | .sr @User Guest")
.Description($"Sets a role for a given user. | `{Prefix}sr @User Guest`")
.Parameter("user_name", ParameterType.Required)
.Parameter("role_name", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles)
@ -133,7 +133,7 @@ namespace NadekoBot.Modules.Administration
});
cgb.CreateCommand(Prefix + "removerole").Alias(Prefix + "rr")
.Description("Removes a role from a given user. | .rr @User Admin")
.Description($"Removes a role from a given user. | `{Prefix}rr @User Admin`")
.Parameter("user_name", ParameterType.Required)
.Parameter("role_name", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles)
@ -204,7 +204,7 @@ namespace NadekoBot.Modules.Administration
});
cgb.CreateCommand(Prefix + "removeallroles").Alias(Prefix + "rar")
.Description("Removes all roles from a mentioned user. | .rar @User")
.Description($"Removes all roles from a mentioned user. | `{Prefix}rar @User`")
.Parameter("user_name", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e =>
@ -230,7 +230,7 @@ namespace NadekoBot.Modules.Administration
});
cgb.CreateCommand(Prefix + "createrole").Alias(Prefix + "cr")
.Description("Creates a role with a given name.**Usage**: `.r Awesome Role`")
.Description($"Creates a role with a given name. | `{Prefix}cr Awesome Role`")
.Parameter("role_name", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.CanManageRoles)
.Do(async e =>
@ -253,7 +253,7 @@ namespace NadekoBot.Modules.Administration
.Parameter("r", ParameterType.Optional)
.Parameter("g", ParameterType.Optional)
.Parameter("b", ParameterType.Optional)
.Description("Set a role's color to the hex or 0-255 rgb color value provided. | `.color Admin 255 200 100` or `.color Admin ffba55`")
.Description($"Set a role's color to the hex or 0-255 rgb color value provided. | `{Prefix}rc Admin 255 200 100` or `{Prefix}rc Admin ffba55`")
.Do(async e =>
{
if (!e.User.ServerPermissions.ManageRoles)
@ -298,7 +298,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "ban").Alias(Prefix + "b")
.Parameter("user", ParameterType.Required)
.Parameter("msg", ParameterType.Unparsed)
.Description("Bans a user by id or name with an optional message. | .b \"@some Guy\" Your behaviour is toxic.")
.Description($"Bans a user by id or name with an optional message. | `{Prefix}b \"@some Guy\" Your behaviour is toxic.`")
.Do(async e =>
{
var msg = e.GetArg("msg");
@ -333,7 +333,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "softban").Alias(Prefix + "sb")
.Parameter("user", ParameterType.Required)
.Parameter("msg", ParameterType.Unparsed)
.Description("Bans and then unbans a user by id or name with an optional message. | .sb \"@some Guy\" Your behaviour is toxic.")
.Description($"Bans and then unbans a user by id or name with an optional message. | `{Prefix}sb \"@some Guy\" Your behaviour is toxic.`")
.Do(async e =>
{
var msg = e.GetArg("msg");
@ -369,7 +369,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "kick").Alias(Prefix + "k")
.Parameter("user")
.Parameter("msg", ParameterType.Unparsed)
.Description("Kicks a mentioned user.")
.Description($"Kicks a mentioned user. | `{Prefix}k \"@some Guy\" Your behaviour is toxic.`")
.Do(async e =>
{
var msg = e.GetArg("msg");
@ -400,7 +400,7 @@ namespace NadekoBot.Modules.Administration
}
});
cgb.CreateCommand(Prefix + "mute")
.Description("Mutes mentioned user or users.")
.Description($"Mutes mentioned user or users. | `{Prefix}mute \"@Someguy\"` or `{Prefix}mute \"@Someguy\" \"@Someguy\"`")
.Parameter("throwaway", ParameterType.Unparsed)
.Do(async e =>
{
@ -426,7 +426,7 @@ namespace NadekoBot.Modules.Administration
});
cgb.CreateCommand(Prefix + "unmute")
.Description("Unmutes mentioned user or users.")
.Description($"Unmutes mentioned user or users. | `{Prefix}unmute \"@Someguy\"` or `{Prefix}unmute \"@Someguy\" \"@Someguy\"`")
.Parameter("throwaway", ParameterType.Unparsed)
.Do(async e =>
{
@ -453,7 +453,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "deafen")
.Alias(Prefix + "deaf")
.Description("Deafens mentioned user or users")
.Description($"Deafens mentioned user or users | `{Prefix}deaf \"@Someguy\"` or `{Prefix}deaf \"@Someguy\" \"@Someguy\"`")
.Parameter("throwaway", ParameterType.Unparsed)
.Do(async e =>
{
@ -480,7 +480,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "undeafen")
.Alias(Prefix + "undef")
.Description("Undeafens mentioned user or users")
.Description($"Undeafens mentioned user or users | `{Prefix}undef \"@Someguy\"` or `{Prefix}undef \"@Someguy\" \"@Someguy\"`")
.Parameter("throwaway", ParameterType.Unparsed)
.Do(async e =>
{
@ -507,7 +507,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "delvoichanl")
.Alias(Prefix + "dvch")
.Description("Deletes a voice channel with a given name.")
.Description($"Deletes a voice channel with a given name. | `{Prefix}dvch VoiceChannelName`")
.Parameter("channel_name", ParameterType.Required)
.Do(async e =>
{
@ -530,7 +530,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "creatvoichanl")
.Alias(Prefix + "cvch")
.Description("Creates a new voice channel with a given name.")
.Description($"Creates a new voice channel with a given name. | `{Prefix}cvch VoiceChannelName`")
.Parameter("channel_name", ParameterType.Required)
.Do(async e =>
{
@ -550,7 +550,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "deltxtchanl")
.Alias(Prefix + "dtch")
.Description("Deletes a text channel with a given name.")
.Description($"Deletes a text channel with a given name. | `{Prefix}dtch TextChannelName`")
.Parameter("channel_name", ParameterType.Required)
.Do(async e =>
{
@ -572,7 +572,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "creatxtchanl")
.Alias(Prefix + "ctch")
.Description("Creates a new text channel with a given name.")
.Description($"Creates a new text channel with a given name. | `{Prefix}ctch TextChannelName`")
.Parameter("channel_name", ParameterType.Required)
.Do(async e =>
{
@ -604,7 +604,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "setchanlname")
.Alias(Prefix + "schn")
.Description("Changed the name of the current channel.")
.Description($"Changed the name of the current channel.| `{Prefix}schn NewName`")
.AddCheck(SimpleCheckers.ManageChannels())
.Parameter("name", ParameterType.Unparsed)
.Do(async e =>
@ -636,7 +636,8 @@ namespace NadekoBot.Modules.Administration
Message[] msgs;
if (string.IsNullOrWhiteSpace(e.GetArg("user_or_num"))) // if nothing is set, clear nadeko's messages, no permissions required
{
msgs = (await e.Channel.DownloadMessages(100).ConfigureAwait(false)).Where(m => m.User.Id == e.Server.CurrentUser.Id).ToArray();
msgs = (await e.Channel.DownloadMessages(100).ConfigureAwait(false));//.Where(m => m.User.Id == e.Server.CurrentUser.Id).ToArray();
msgs = msgs.Where(m => m.User.Id == e.Server.CurrentUser.Id).ToArray();
if (!msgs.Any())
return;
await e.Channel.DeleteMessages(msgs).ConfigureAwait(false);
@ -684,7 +685,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "setname")
.Alias(Prefix + "newnm")
.Description("Give the bot a new name. **Bot Owner Only!**")
.Description($"Give the bot a new name. **Bot Owner Only!** | {Prefix}newnm BotName")
.Parameter("new_name", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>
@ -696,7 +697,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "newavatar")
.Alias(Prefix + "setavatar")
.Description("Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot Owner Only!** | `.setavatar https://i.ytimg.com/vi/WDudkR1eTMM/maxresdefault.jpg`")
.Description($"Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot Owner Only!** | `{Prefix}setavatar https://i.ytimg.com/vi/WDudkR1eTMM/maxresdefault.jpg`")
.Parameter("img", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>
@ -717,7 +718,7 @@ namespace NadekoBot.Modules.Administration
});
cgb.CreateCommand(Prefix + "setgame")
.Description("Sets the bots game. **Bot Owner Only!**")
.Description($"Sets the bots game. **Bot Owner Only!** | `{Prefix}setgame Playing with kwoth`")
.Parameter("set_game", ParameterType.Unparsed)
.Do(e =>
{
@ -727,7 +728,7 @@ namespace NadekoBot.Modules.Administration
});
cgb.CreateCommand(Prefix + "send")
.Description("Send a message to someone on a different server through the bot. **Bot Owner Only!** | `.send serverid|u:user_id Send this to a user!` or `.send serverid|c:channel_id Send this to a channel!`")
.Description($"Send a message to someone on a different server through the bot. **Bot Owner Only!** | `{Prefix}send serverid|u:user_id Send this to a user!` or `{Prefix}send serverid|c:channel_id Send this to a channel!`")
.Parameter("ids", ParameterType.Required)
.Parameter("msg", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly())
@ -775,7 +776,7 @@ namespace NadekoBot.Modules.Administration
cgb.CreateCommand(Prefix + "mentionrole")
.Alias(Prefix + "menro")
.Description("Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission.")
.Description($"Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission. | `{Prefix}menro RoleName`")
.Parameter("roles", ParameterType.Unparsed)
.Do(async e =>
{
@ -828,7 +829,7 @@ namespace NadekoBot.Modules.Administration
});
cgb.CreateCommand(Prefix + "donadd")
.Description("Add a donator to the database.")
.Description($"Add a donator to the database. | `.donadd Donate Amount`")
.Parameter("donator")
.Parameter("amount")
.AddCheck(SimpleCheckers.OwnerOnly())
@ -854,7 +855,7 @@ namespace NadekoBot.Modules.Administration
});
cgb.CreateCommand(Prefix + "announce")
.Description($"Sends a message to all servers' general channel bot is connected to.**Bot Owner Only!** | {Prefix}announce Useless spam")
.Description($"Sends a message to all servers' general channel bot is connected to.**Bot Owner Only!** | `{Prefix}announce Useless spam`")
.Parameter("msg", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>
@ -868,7 +869,7 @@ namespace NadekoBot.Modules.Administration
});
cgb.CreateCommand(Prefix + "savechat")
.Description("Saves a number of messages to a text file and sends it to you. **Bot Owner Only** | `.chatsave 150`")
.Description($"Saves a number of messages to a text file and sends it to you. **Bot Owner Only** | `{Prefix}savechat 150`")
.Parameter("cnt", ParameterType.Required)
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>

View File

@ -40,7 +40,7 @@ namespace NadekoBot.Modules.Administration.Commands
NadekoBot.Config.CustomReactions[name].Add(message);
else
NadekoBot.Config.CustomReactions.Add(name, new System.Collections.Generic.List<string>() { message });
await Task.Run(() => Classes.JSONModels.ConfigHandler.SaveConfig()).ConfigureAwait(false);
await Classes.JSONModels.ConfigHandler.SaveConfig().ConfigureAwait(false);
await e.Channel.SendMessage($"Added {name} : {message}").ConfigureAwait(false);
});
@ -140,7 +140,7 @@ namespace NadekoBot.Modules.Administration.Commands
index = index - 1;
NadekoBot.Config.CustomReactions[name][index] = msg;
await Task.Run(() => Classes.JSONModels.ConfigHandler.SaveConfig()).ConfigureAwait(false);
await Classes.JSONModels.ConfigHandler.SaveConfig().ConfigureAwait(false);
await e.Channel.SendMessage($"Edited response #{index + 1} from `{name}`").ConfigureAwait(false);
});
@ -183,7 +183,7 @@ namespace NadekoBot.Modules.Administration.Commands
NadekoBot.Config.CustomReactions.Remove(name);
message = $"Deleted custom reaction: `{name}`";
}
await Task.Run(() => Classes.JSONModels.ConfigHandler.SaveConfig()).ConfigureAwait(false);
await Classes.JSONModels.ConfigHandler.SaveConfig().ConfigureAwait(false);
await e.Channel.SendMessage(message).ConfigureAwait(false);
});
}

View File

@ -7,8 +7,10 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using Timer = System.Timers.Timer;
namespace NadekoBot.Modules.Administration.Commands
{
@ -36,7 +38,7 @@ namespace NadekoBot.Modules.Administration.Commands
{"%trivia%", () => Games.Commands.TriviaCommands.RunningTrivias.Count.ToString()}
};
private readonly object playingPlaceholderLock = new object();
private readonly SemaphoreSlim playingPlaceholderLock = new SemaphoreSlim(1,1);
public PlayingRotate(DiscordModule module) : base(module)
{
@ -47,7 +49,9 @@ namespace NadekoBot.Modules.Administration.Commands
{
i++;
var status = "";
lock (playingPlaceholderLock)
//wtf am i doing, just use a queue ffs
await playingPlaceholderLock.WaitAsync().ConfigureAwait(false);
try
{
if (PlayingPlaceholders.Count == 0
|| NadekoBot.Config.RotatingStatuses.Count == 0
@ -59,6 +63,7 @@ namespace NadekoBot.Modules.Administration.Commands
status = PlayingPlaceholders.Aggregate(status,
(current, kvp) => current.Replace(kvp.Key, kvp.Value()));
}
finally { playingPlaceholderLock.Release(); }
if (string.IsNullOrWhiteSpace(status))
return;
await Task.Run(() => { NadekoBot.Client.SetGame(status); });
@ -71,14 +76,18 @@ namespace NadekoBot.Modules.Administration.Commands
public Func<CommandEventArgs, Task> DoFunc() => async e =>
{
lock (playingPlaceholderLock)
await playingPlaceholderLock.WaitAsync().ConfigureAwait(false);
try
{
if (timer.Enabled)
timer.Stop();
else
timer.Start();
NadekoBot.Config.IsRotatingStatus = timer.Enabled;
ConfigHandler.SaveConfig();
await ConfigHandler.SaveConfig().ConfigureAwait(false);
}
finally {
playingPlaceholderLock.Release();
}
await e.Channel.SendMessage($"❗`Rotating playing status has been {(timer.Enabled ? "enabled" : "disabled")}.`").ConfigureAwait(false);
};
@ -102,10 +111,15 @@ namespace NadekoBot.Modules.Administration.Commands
var arg = e.GetArg("text");
if (string.IsNullOrWhiteSpace(arg))
return;
lock (playingPlaceholderLock)
await playingPlaceholderLock.WaitAsync().ConfigureAwait(false);
try
{
NadekoBot.Config.RotatingStatuses.Add(arg);
ConfigHandler.SaveConfig();
await ConfigHandler.SaveConfig();
}
finally
{
playingPlaceholderLock.Release();
}
await e.Channel.SendMessage("🆗 `Added a new playing string.`").ConfigureAwait(false);
});
@ -137,14 +151,15 @@ namespace NadekoBot.Modules.Administration.Commands
var arg = e.GetArg("number");
int num;
string str;
lock (playingPlaceholderLock)
{
await playingPlaceholderLock.WaitAsync().ConfigureAwait(false);
try {
if (!int.TryParse(arg.Trim(), out num) || num <= 0 || num > NadekoBot.Config.RotatingStatuses.Count)
return;
str = NadekoBot.Config.RotatingStatuses[num - 1];
NadekoBot.Config.RotatingStatuses.RemoveAt(num - 1);
ConfigHandler.SaveConfig();
await ConfigHandler.SaveConfig().ConfigureAwait(false);
}
finally { playingPlaceholderLock.Release(); }
await e.Channel.SendMessage($"🆗 `Removed playing string #{num}`({str})").ConfigureAwait(false);
});
}

View File

@ -1,9 +1,8 @@
using Discord.Commands;
using Newtonsoft.Json;
using System;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
//using Manatee.Json.Serialization;
namespace NadekoBot.Classes.ClashOfClans
{
@ -11,16 +10,22 @@ namespace NadekoBot.Classes.ClashOfClans
{
One, Two, Three
}
public enum WarState
{
Started, Ended, Created
}
[System.Serializable]
internal class Caller
{
public string CallUser { get; }
public string CallUser { get; set; }
public DateTime TimeAdded { get; private set; }
public DateTime TimeAdded { get; set; }
public bool BaseDestroyed { get; internal set; }
public bool BaseDestroyed { get; set; }
public int Stars { get; set; } = 3;
public Caller() { }
public Caller(string callUser, DateTime timeAdded, bool baseDestroyed)
{
@ -31,7 +36,7 @@ namespace NadekoBot.Classes.ClashOfClans
public void ResetTime()
{
TimeAdded = DateTime.Now;
TimeAdded = DateTime.UtcNow;
}
public void Destroy()
@ -44,97 +49,84 @@ namespace NadekoBot.Classes.ClashOfClans
{
private static TimeSpan callExpire => new TimeSpan(2, 0, 0);
public string EnemyClan { get; }
public int Size { get; }
public string EnemyClan { get; set; }
public int Size { get; set; }
private Caller[] bases { get; }
private CancellationTokenSource[] baseCancelTokens;
private CancellationTokenSource endTokenSource { get; } = new CancellationTokenSource();
public event Action<string> OnUserTimeExpired = delegate { };
public event Action OnWarEnded = delegate { };
public bool Started { get; set; } = false;
public Caller[] Bases { get; set; }
public WarState WarState { get; set; } = WarState.Created;
//public bool Started { get; set; } = false;
public DateTime StartedAt { get; set; }
//public bool Ended { get; private set; } = false;
public ClashWar(string enemyClan, int size, CommandEventArgs e)
public ulong ServerId { get; set; }
public ulong ChannelId { get; set; }
[JsonIgnore]
public Discord.Channel Channel { get; internal set; }
/// <summary>
/// This init is purely for the deserialization
/// </summary>
public ClashWar() { }
public ClashWar(string enemyClan, int size, ulong serverId, ulong channelId)
{
this.EnemyClan = enemyClan;
this.Size = size;
this.bases = new Caller[size];
this.baseCancelTokens = new CancellationTokenSource[size];
this.Bases = new Caller[size];
this.ServerId = serverId;
this.ChannelId = channelId;
this.Channel = NadekoBot.Client.Servers.FirstOrDefault(s => s.Id == serverId)?.TextChannels.FirstOrDefault(c => c.Id == channelId);
}
internal void End()
{
if (endTokenSource.Token.IsCancellationRequested) return;
endTokenSource.Cancel();
OnWarEnded();
//Ended = true;
WarState = WarState.Ended;
}
internal void Call(string u, int baseNumber)
{
if (baseNumber < 0 || baseNumber >= bases.Length)
if (baseNumber < 0 || baseNumber >= Bases.Length)
throw new ArgumentException("Invalid base number");
if (bases[baseNumber] != null)
if (Bases[baseNumber] != null)
throw new ArgumentException("That base is already claimed.");
for (var i = 0; i < bases.Length; i++)
for (var i = 0; i < Bases.Length; i++)
{
if (bases[i]?.BaseDestroyed == false && bases[i]?.CallUser == u)
throw new ArgumentException($"@{u} You already claimed a base #{i + 1}. You can't claim a new one.");
if (Bases[i]?.BaseDestroyed == false && Bases[i]?.CallUser == u)
throw new ArgumentException($"@{u} You already claimed base #{i + 1}. You can't claim a new one.");
}
bases[baseNumber] = new Caller(u.Trim(), DateTime.Now, false);
Bases[baseNumber] = new Caller(u.Trim(), DateTime.UtcNow, false);
}
internal async Task Start()
internal void Start()
{
if (Started)
throw new InvalidOperationException();
try
{
Started = true;
foreach (var b in bases.Where(b => b != null))
if (WarState == WarState.Started)
throw new InvalidOperationException("War already started");
//if (Started)
// throw new InvalidOperationException();
//Started = true;
WarState = WarState.Started;
StartedAt = DateTime.UtcNow;
foreach (var b in Bases.Where(b => b != null))
{
b.ResetTime();
}
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
Task.Run(async () => await ClearArray()).ConfigureAwait(false);
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
await Task.Delay(new TimeSpan(24, 0, 0), endTokenSource.Token).ConfigureAwait(false);
}
catch { }
finally
{
End();
}
}
internal int Uncall(string user)
{
user = user.Trim();
for (var i = 0; i < bases.Length; i++)
for (var i = 0; i < Bases.Length; i++)
{
if (bases[i]?.CallUser != user) continue;
bases[i] = null;
if (Bases[i]?.CallUser != user) continue;
Bases[i] = null;
return i;
}
throw new InvalidOperationException("You are not participating in that war.");
}
private async Task ClearArray()
{
while (!endTokenSource.IsCancellationRequested)
{
await Task.Delay(5000).ConfigureAwait(false);
for (var i = 0; i < bases.Length; i++)
{
if (bases[i] == null) continue;
if (!bases[i].BaseDestroyed && DateTime.Now - bases[i].TimeAdded >= callExpire)
{
OnUserTimeExpired(bases[i].CallUser);
bases[i] = null;
}
}
}
}
public string ShortPrint() =>
$"`{EnemyClan}` ({Size} v {Size})";
@ -143,24 +135,24 @@ namespace NadekoBot.Classes.ClashOfClans
var sb = new StringBuilder();
sb.AppendLine($"🔰**WAR AGAINST `{EnemyClan}` ({Size} v {Size}) INFO:**");
if (!Started)
if (WarState == WarState.Created)
sb.AppendLine("`not started`");
for (var i = 0; i < bases.Length; i++)
for (var i = 0; i < Bases.Length; i++)
{
if (bases[i] == null)
if (Bases[i] == null)
{
sb.AppendLine($"`{i + 1}.` ❌*unclaimed*");
}
else
{
if (bases[i].BaseDestroyed)
if (Bases[i].BaseDestroyed)
{
sb.AppendLine($"`{i + 1}.` ✅ `{bases[i].CallUser}` {new string('⭐', bases[i].Stars)}");
sb.AppendLine($"`{i + 1}.` ✅ `{Bases[i].CallUser}` {new string('⭐', Bases[i].Stars)}");
}
else
{
var left = Started ? callExpire - (DateTime.Now - bases[i].TimeAdded) : callExpire;
sb.AppendLine($"`{i + 1}.` ✅ `{bases[i].CallUser}` {left.Hours}h {left.Minutes}m {left.Seconds}s left");
var left = (WarState == WarState.Started) ? callExpire - (DateTime.UtcNow - Bases[i].TimeAdded) : callExpire;
sb.AppendLine($"`{i + 1}.` ✅ `{Bases[i].CallUser}` {left.Hours}h {left.Minutes}m {left.Seconds}s left");
}
}
@ -171,11 +163,11 @@ namespace NadekoBot.Classes.ClashOfClans
internal int FinishClaim(string user, int stars = 3)
{
user = user.Trim();
for (var i = 0; i < bases.Length; i++)
for (var i = 0; i < Bases.Length; i++)
{
if (bases[i]?.BaseDestroyed != false || bases[i]?.CallUser != user) continue;
bases[i].BaseDestroyed = true;
bases[i].Stars = stars;
if (Bases[i]?.BaseDestroyed != false || Bases[i]?.CallUser != user) continue;
Bases[i].BaseDestroyed = true;
Bases[i].Stars = stars;
return i;
}
throw new InvalidOperationException($"@{user} You are either not participating in that war, or you already destroyed a base.");

View File

@ -1,12 +1,15 @@
using Discord.Commands;
using Discord.Modules;
using NadekoBot.Classes.ClashOfClans;
using NadekoBot.Modules.Permissions.Classes;
using Newtonsoft.Json;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NadekoBot.Modules.Permissions.Classes;
namespace NadekoBot.Modules.ClashOfClans
{
@ -14,10 +17,128 @@ namespace NadekoBot.Modules.ClashOfClans
{
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.ClashOfClans;
public static ConcurrentDictionary<ulong, List<ClashWar>> ClashWars { get; } = new ConcurrentDictionary<ulong, List<ClashWar>>();
public static ConcurrentDictionary<ulong, List<ClashWar>> ClashWars { get; set; } = new ConcurrentDictionary<ulong, List<ClashWar>>();
private readonly object writeLock = new object();
public ClashOfClansModule()
{
NadekoBot.OnReady += () => Task.Run(async () =>
{
if (File.Exists("data/clashofclans/wars.json"))
{
try
{
var content = File.ReadAllText("data/clashofclans/wars.json");
var dict = JsonConvert.DeserializeObject<Dictionary<ulong, List<ClashWar>>>(content);
foreach (var cw in dict)
{
cw.Value.ForEach(war =>
{
war.Channel = NadekoBot.Client.GetServer(war.ServerId)?.GetChannel(war.ChannelId);
if (war.Channel == null)
{
cw.Value.Remove(war);
}
}
);
}
//urgh
ClashWars = new ConcurrentDictionary<ulong, List<ClashWar>>(dict);
}
catch (Exception e)
{
Console.WriteLine("Could not load coc wars: " + e.Message);
}
}
//Can't this be disabled if the modules is disabled too :)
var callExpire = new TimeSpan(2, 0, 0);
var warExpire = new TimeSpan(23, 0, 0);
while (true)
{
try
{
var hash = ClashWars.GetHashCode();
foreach (var cw in ClashWars)
{
foreach (var war in cw.Value)
{
await CheckWar(callExpire, war);
}
List<ClashWar> newVal = new List<ClashWar>();
foreach (var w in cw.Value)
{
//We add when A: the war is not ended
if (w.WarState != WarState.Ended)
{
//and B: the war has not expired
if ((w.WarState == WarState.Started && DateTime.UtcNow - w.StartedAt <= warExpire) || w.WarState == WarState.Created)
{
newVal.Add(w);
}
}
}
//var newVal = cw.Value.Where(w => !(w.Ended || DateTime.UtcNow - w.StartedAt >= warExpire)).ToList();
foreach (var exWar in cw.Value.Except(newVal))
{
await exWar.Channel.SendMessage($"War against {exWar.EnemyClan} ({exWar.Size}v{exWar.Size}) has ended");
}
if (newVal.Count == 0)
{
List<ClashWar> obj;
ClashWars.TryRemove(cw.Key, out obj);
}
else
{
ClashWars.AddOrUpdate(cw.Key, newVal, (x, s) => newVal);
}
}
if (hash != ClashWars.GetHashCode()) //something changed
{
Save();
}
}
catch { }
await Task.Delay(5000);
}
});
}
private static void Save()
{
try
{
Directory.CreateDirectory("data/clashofclans");
File.WriteAllText("data/clashofclans/wars.json", JsonConvert.SerializeObject(ClashWars, Formatting.Indented));
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
private static async Task CheckWar(TimeSpan callExpire, ClashWar war)
{
var Bases = war.Bases;
for (var i = 0; i < Bases.Length; i++)
{
if (Bases[i] == null) continue;
if (!Bases[i].BaseDestroyed && DateTime.UtcNow - Bases[i].TimeAdded >= callExpire)
{
await war.Channel.SendMessage($"❗🔰**Claim from @{Bases[i].CallUser} for a war against {war.ShortPrint()} has expired.**").ConfigureAwait(false);
Bases[i] = null;
}
}
}
#region commands
public override void Install(ModuleManager manager)
{
manager.CreateCommands("", cgb =>
@ -34,13 +155,6 @@ namespace NadekoBot.Modules.ClashOfClans
{
if (!e.User.ServerPermissions.ManageChannels)
return;
List<ClashWar> wars;
if (!ClashWars.TryGetValue(e.Server.Id, out wars))
{
wars = new List<ClashWar>();
if (!ClashWars.TryAdd(e.Server.Id, wars))
return;
}
var enemyClan = e.GetArg("enemy_clan");
if (string.IsNullOrWhiteSpace(enemyClan))
{
@ -52,29 +166,21 @@ namespace NadekoBot.Modules.ClashOfClans
await e.Channel.SendMessage("💢🔰 Not a Valid war size").ConfigureAwait(false);
return;
}
var cw = new ClashWar(enemyClan, size, e);
List<ClashWar> wars;
if (!ClashWars.TryGetValue(e.Server.Id, out wars))
{
wars = new List<ClashWar>();
if (!ClashWars.TryAdd(e.Server.Id, wars))
return;
}
var cw = new ClashWar(enemyClan, size, e.Server.Id, e.Channel.Id);
//cw.Start();
wars.Add(cw);
cw.OnUserTimeExpired += async (u) =>
{
try
{
await
e.Channel.SendMessage(
$"❗🔰**Claim from @{u} for a war against {cw.ShortPrint()} has expired.**")
.ConfigureAwait(false);
}
catch { }
};
cw.OnWarEnded += async () =>
{
try
{
await e.Channel.SendMessage($"❗🔰**War against {cw.ShortPrint()} ended.**").ConfigureAwait(false);
}
catch { }
};
await e.Channel.SendMessage($"❗🔰**CREATED CLAN WAR AGAINST {cw.ShortPrint()}**").ConfigureAwait(false);
Save();
//war with the index X started.
});
@ -93,14 +199,14 @@ namespace NadekoBot.Modules.ClashOfClans
var war = warsInfo.Item1[warsInfo.Item2];
try
{
var startTask = war.Start();
war.Start();
await e.Channel.SendMessage($"🔰**STARTED WAR AGAINST {war.ShortPrint()}**").ConfigureAwait(false);
await startTask.ConfigureAwait(false);
}
catch
{
await e.Channel.SendMessage($"🔰**WAR AGAINST {war.ShortPrint()} IS ALREADY STARTED**").ConfigureAwait(false);
await e.Channel.SendMessage($"🔰**WAR AGAINST {war.ShortPrint()} HAS ALREADY STARTED**").ConfigureAwait(false);
}
Save();
});
cgb.CreateCommand(Prefix + "listwar")
@ -132,6 +238,7 @@ namespace NadekoBot.Modules.ClashOfClans
}
await e.Channel.SendMessage(sb.ToString()).ConfigureAwait(false);
return;
}
//if number is not null, print the war needed
var warsInfo = GetInfo(e);
@ -173,6 +280,7 @@ namespace NadekoBot.Modules.ClashOfClans
var war = warsInfo.Item1[warsInfo.Item2];
war.Call(usr, baseNum - 1);
await e.Channel.SendMessage($"🔰**{usr}** claimed a base #{baseNum} for a war against {war.ShortPrint()}").ConfigureAwait(false);
Save();
}
catch (Exception ex)
{
@ -206,7 +314,7 @@ namespace NadekoBot.Modules.ClashOfClans
cgb.CreateCommand(Prefix + "unclaim")
.Alias(Prefix + "uncall")
.Alias(Prefix + "uc")
.Description($"Removes your claim from a certain war. Optional second argument denotes a person in whos place to unclaim | {Prefix}uc [war_number] [optional_other_name]")
.Description($"Removes your claim from a certain war. Optional second argument denotes a person in whose place to unclaim | {Prefix}uc [war_number] [optional_other_name]")
.Parameter("number", ParameterType.Required)
.Parameter("other_name", ParameterType.Unparsed)
.Do(async e =>
@ -226,6 +334,7 @@ namespace NadekoBot.Modules.ClashOfClans
var war = warsInfo.Item1[warsInfo.Item2];
var baseNumber = war.Uncall(usr);
await e.Channel.SendMessage($"🔰 @{usr} has **UNCLAIMED** a base #{baseNumber + 1} from a war against {war.ShortPrint()}").ConfigureAwait(false);
Save();
}
catch (Exception ex)
{
@ -246,12 +355,17 @@ namespace NadekoBot.Modules.ClashOfClans
return;
}
warsInfo.Item1[warsInfo.Item2].End();
await e.Channel.SendMessage($"❗🔰**War against {warsInfo.Item1[warsInfo.Item2].ShortPrint()} ended.**").ConfigureAwait(false);
var size = warsInfo.Item1[warsInfo.Item2].Size;
warsInfo.Item1.RemoveAt(warsInfo.Item2);
Save();
});
});
}
#endregion
private async Task FinishClaim(CommandEventArgs e, int stars = 3)
{
@ -271,6 +385,7 @@ namespace NadekoBot.Modules.ClashOfClans
{
var baseNum = war.FinishClaim(usr, stars);
await e.Channel.SendMessage($"❗🔰{e.User.Mention} **DESTROYED** a base #{baseNum + 1} in a war against {war.ShortPrint()}").ConfigureAwait(false);
Save();
}
catch (Exception ex)
{

View File

@ -33,7 +33,7 @@ namespace NadekoBot.Modules.Conversations
cgb.AddCheck(PermissionChecker.Instance);
cgb.CreateCommand("..")
.Description("Adds a new quote with the specified name (single word) and message (no limit). | .. abc My message")
.Description("Adds a new quote with the specified name (single word) and message (no limit). | `.. abc My message`")
.Parameter("keyword", ParameterType.Required)
.Parameter("text", ParameterType.Unparsed)
.Do(async e =>
@ -54,7 +54,7 @@ namespace NadekoBot.Modules.Conversations
});
cgb.CreateCommand("...")
.Description("Shows a random quote with a specified name. | .. abc")
.Description("Shows a random quote with a specified name. | `... abc`")
.Parameter("keyword", ParameterType.Required)
.Do(async e =>
{

View File

@ -0,0 +1,289 @@
using NadekoBot.Classes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Discord.Commands;
using System.Collections.Concurrent;
using Discord;
using NadekoBot.Extensions;
using System.Threading;
namespace NadekoBot.Modules.Gambling.Commands
{
class AnimalRacing : DiscordCommand
{
public static ConcurrentDictionary<ulong, AnimalRace> AnimalRaces = new ConcurrentDictionary<ulong, AnimalRace>();
public AnimalRacing(DiscordModule module) : base(module)
{
}
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Prefix + "race")
.Description("Starts a new animal race.")
.Do(e => {
var ar = new AnimalRace(e.Server.Id, e.Channel);
if (ar.Fail)
{
return;
}
});
cgb.CreateCommand(Prefix + "joinrace")
.Alias(Prefix + "jr")
.Description("Joins a new race. You can specify an amount of flowers for betting (optional). You will get YourBet*(participants-1) back if you win. | `$jr` or `$jr 5`")
.Parameter("amount", ParameterType.Optional)
.Do(async e => {
int amount;
if (!int.TryParse(e.GetArg("amount"), out amount) || amount < 0)
amount = 0;
var userFlowers = GamblingModule.GetUserFlowers(e.User.Id);
if (userFlowers < amount)
{
await e.Channel.SendMessage($"{e.User.Mention} You don't have enough {NadekoBot.Config.CurrencyName}s. You only have {userFlowers}{NadekoBot.Config.CurrencySign}.").ConfigureAwait(false);
return;
}
if (amount > 0)
await FlowersHandler.RemoveFlowers(e.User, "BetRace", (int)amount, true).ConfigureAwait(false);
AnimalRace ar;
if (!AnimalRaces.TryGetValue(e.Server.Id, out ar)) {
await e.Channel.SendMessage("No race exists on this server");
}
await ar.JoinRace(e.User, amount);
});
}
public class AnimalRace
{
private ConcurrentQueue<string> animals = new ConcurrentQueue<string>(NadekoBot.Config.RaceAnimals.Shuffle());
public bool Fail { get; internal set; }
public List<Participant> participants = new List<Participant>();
private ulong serverId;
private int messagesSinceGameStarted = 0;
public Channel raceChannel { get; set; }
public bool Started { get; private set; } = false;
public AnimalRace(ulong serverId, Channel ch)
{
this.serverId = serverId;
this.raceChannel = ch;
if (!AnimalRaces.TryAdd(serverId, this))
{
Fail = true;
return;
}
var cancelSource = new CancellationTokenSource();
var token = cancelSource.Token;
var fullgame = CheckForFullGameAsync(token);
Task.Run(async () =>
{
try
{
await raceChannel.SendMessage($"🏁`Race is starting in 20 seconds or when the room is full. Type $jr to join the race.`");
var t = await Task.WhenAny(Task.Delay(20000, token), fullgame);
Started = true;
cancelSource.Cancel();
if (t == fullgame)
{
await raceChannel.SendMessage("🏁`Race full, starting right now!`");
}
else if (participants.Count > 1)
{
await raceChannel.SendMessage("🏁`Game starting with " + participants.Count + " praticipants.`");
}
else
{
await raceChannel.SendMessage("🏁`Race failed to start since there was not enough participants.`");
var p = participants.FirstOrDefault();
if (p != null)
await FlowersHandler.AddFlowersAsync(p.User, "BetRace", p.AmountBet, true).ConfigureAwait(false);
End();
return;
}
await Task.Run(StartRace);
End();
}
catch { }
});
}
private void End()
{
AnimalRace throwaway;
AnimalRaces.TryRemove(serverId, out throwaway);
}
private async Task StartRace() {
var rng = new Random();
Participant winner = null;
Message msg = null;
int place = 1;
try
{
NadekoBot.Client.MessageReceived += Client_MessageReceived;
while (!participants.All(p => p.Total >= 60))
{
//update the state
participants.ForEach(p =>
{
p.Total += 1 + rng.Next(0, 10);
if (p.Total > 60)
{
p.Total = 60;
if (winner == null)
{
winner = p;
}
if (p.Place == 0)
p.Place = place++;
}
});
//draw the state
var text = $@"|🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🔚|
{String.Join("\n", participants.Select(p => $"{(int)(p.Total / 60f * 100),-2}%|{p.ToString()}"))}
|🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🔚|";
if (msg == null || messagesSinceGameStarted >= 10) // also resend the message if channel was spammed
{
if(msg != null)
try { await msg.Delete(); } catch { }
msg = await raceChannel.SendMessage(text);
messagesSinceGameStarted = 0;
}
else
await msg.Edit(text);
await Task.Delay(2500);
}
}
finally
{
NadekoBot.Client.MessageReceived -= Client_MessageReceived;
}
if (winner.AmountBet > 0)
{
var wonAmount = winner.AmountBet * (participants.Count - 1);
await FlowersHandler.AddFlowersAsync(winner.User, "Won a Race", wonAmount).ConfigureAwait(false);
await raceChannel.SendMessage($"🏁 {winner.User.Mention} as {winner.Animal} **Won the race and {wonAmount}{NadekoBot.Config.CurrencySign}!**");
}
else
{
await raceChannel.SendMessage($"🏁 {winner.User.Mention} as {winner.Animal} **Won the race!**");
}
}
private void Client_MessageReceived(object sender, MessageEventArgs e)
{
if (e.Message.IsAuthor || e.Channel.IsPrivate || e.Channel != raceChannel)
return;
messagesSinceGameStarted++;
}
private async Task CheckForFullGameAsync(CancellationToken cancelToken) {
while (animals.Count > 0)
{
await Task.Delay(100,cancelToken);
}
}
public async Task<bool> JoinRace(User u, int amount = 0)
{
var animal = "";
if (!animals.TryDequeue(out animal))
{
await raceChannel.SendMessage($"{u.Mention} `There is no running race on this server.`");
return false;
}
var p = new Participant(u, animal, amount);
if (participants.Contains(p))
{
await raceChannel.SendMessage($"{u.Mention} `You already joined this race.`");
return false;
}
if (Started)
{
await raceChannel.SendMessage($"{u.Mention} `Race is already started`");
return false;
}
participants.Add(p);
await raceChannel.SendMessage($"{u.Mention} **joined the race as a {p.Animal}" + (amount > 0 ? $" and bet {amount} {NadekoBot.Config.CurrencyName.SnPl(amount)}!**" : "**"));
return true;
}
}
public class Participant
{
public User User { get; set; }
public string Animal { get; set; }
public int AmountBet { get; set; }
public float Coeff { get; set; }
public int Total { get; set; }
public int Place { get; set; } = 0;
public Participant(User u, string a, int amount)
{
this.User = u;
this.Animal = a;
this.AmountBet = amount;
}
public override int GetHashCode()
{
return User.GetHashCode();
}
public override bool Equals(object obj)
{
var p = obj as Participant;
return p == null?
false:
p.User == User;
}
public override string ToString()
{
var str = new string('‣', Total) + Animal;
if (Place == 0)
return str;
if (Place == 1)
{
return str + "🏆";
}
else if (Place == 2)
{
return str + "`2nd`";
}
else if (Place == 3)
{
return str + "`3rd`";
}
else {
return str + $"`{Place}th`";
}
}
}
}
}

View File

@ -4,6 +4,7 @@ using Discord.Modules;
using NadekoBot.Classes;
using NadekoBot.DataModels;
using NadekoBot.Extensions;
using NadekoBot.Modules.Gambling.Commands;
using NadekoBot.Modules.Permissions.Classes;
using System;
using System.Linq;
@ -18,6 +19,7 @@ namespace NadekoBot.Modules.Gambling
commands.Add(new DrawCommand(this));
commands.Add(new FlipCoinCommand(this));
commands.Add(new DiceRollCommand(this));
commands.Add(new AnimalRacing(this));
}
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Gambling;
@ -31,7 +33,7 @@ namespace NadekoBot.Modules.Gambling
commands.ForEach(com => com.Init(cgb));
cgb.CreateCommand(Prefix + "raffle")
.Description("Prints a name and ID of a random user from the online list from the (optional) role.")
.Description($"Prints a name and ID of a random user from the online list from the (optional) role. | `{Prefix}raffle` or `{Prefix}raffle RoleName")
.Parameter("role", ParameterType.Optional)
.Do(async e =>
{
@ -93,7 +95,7 @@ namespace NadekoBot.Modules.Gambling
});
cgb.CreateCommand(Prefix + "award")
.Description("Gives someone a certain amount of flowers. **Bot Owner Only!** | `$award 100 @person`")
.Description($"Gives someone a certain amount of flowers. **Bot Owner Only!** | `{Prefix}award 100 @person`")
.AddCheck(SimpleCheckers.OwnerOnly())
.Parameter("amount", ParameterType.Required)
.Parameter("receiver", ParameterType.Unparsed)
@ -115,7 +117,7 @@ namespace NadekoBot.Modules.Gambling
});
cgb.CreateCommand(Prefix + "take")
.Description("Takes a certain amount of flowers from someone. **Bot Owner Only!**")
.Description($"Takes a certain amount of flowers from someone. **Bot Owner Only!** | `{Prefix}take 1 \"@someguy\"`")
.AddCheck(SimpleCheckers.OwnerOnly())
.Parameter("amount", ParameterType.Required)
.Parameter("rektperson", ParameterType.Unparsed)

View File

@ -9,6 +9,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
namespace NadekoBot.Modules.Games.Commands
@ -59,7 +60,7 @@ namespace NadekoBot.Modules.Games.Commands
//channelid/messageid pair
ConcurrentDictionary<ulong, IEnumerable<Message>> plantedFlowerChannels = new ConcurrentDictionary<ulong, IEnumerable<Message>>();
private object locker = new object();
private SemaphoreSlim locker = new SemaphoreSlim(1,1);
internal override void Init(CommandGroupBuilder cgb)
{
@ -78,38 +79,47 @@ namespace NadekoBot.Modules.Games.Commands
await FlowersHandler.AddFlowersAsync(e.User, "Picked a flower.", 1, true).ConfigureAwait(false);
var msg = await e.Channel.SendMessage($"**{e.User.Name}** picked a {NadekoBot.Config.CurrencyName}!").ConfigureAwait(false);
ThreadPool.QueueUserWorkItem(async (state) =>
{
try
{
await Task.Delay(10000).ConfigureAwait(false);
await msg.Delete().ConfigureAwait(false);
}
catch { }
});
});
cgb.CreateCommand(Module.Prefix + "plant")
.Description("Spend a flower to plant it in this channel. (If bot is restarted or crashes, flower will be lost)")
.Do(e =>
.Do(async e =>
{
lock (locker)
await locker.WaitAsync().ConfigureAwait(false);
try
{
if (plantedFlowerChannels.ContainsKey(e.Channel.Id))
{
e.Channel.SendMessage($"There is already a {NadekoBot.Config.CurrencyName} in this channel.");
await e.Channel.SendMessage($"There is already a {NadekoBot.Config.CurrencyName} in this channel.").ConfigureAwait(false);
return;
}
var removed = FlowersHandler.RemoveFlowers(e.User, "Planted a flower.", 1, true).GetAwaiter().GetResult();
var removed = await FlowersHandler.RemoveFlowers(e.User, "Planted a flower.", 1, true).ConfigureAwait(false);
if (!removed)
{
e.Channel.SendMessage($"You don't have any {NadekoBot.Config.CurrencyName}s.").Wait();
await e.Channel.SendMessage($"You don't have any {NadekoBot.Config.CurrencyName}s.").ConfigureAwait(false);
return;
}
var file = GetRandomCurrencyImagePath();
Message msg;
if (file == null)
msg = e.Channel.SendMessage(NadekoBot.Config.CurrencySign).GetAwaiter().GetResult();
msg = await e.Channel.SendMessage(NadekoBot.Config.CurrencySign).ConfigureAwait(false);
else
msg = e.Channel.SendFile(file).GetAwaiter().GetResult();
msg = await e.Channel.SendFile(file).ConfigureAwait(false);
var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.Config.CurrencyName[0]);
var msg2 = e.Channel.SendMessage($"Oh how Nice! **{e.User.Name}** planted {(vowelFirst ? "an" : "a")} {NadekoBot.Config.CurrencyName}. Pick it using {Module.Prefix}pick").GetAwaiter().GetResult();
var msg2 = await e.Channel.SendMessage($"Oh how Nice! **{e.User.Name}** planted {(vowelFirst ? "an" : "a")} {NadekoBot.Config.CurrencyName}. Pick it using {Module.Prefix}pick").ConfigureAwait(false);
plantedFlowerChannels.TryAdd(e.Channel.Id, new[] { msg, msg2 });
}
finally { locker.Release(); }
});
cgb.CreateCommand(Prefix + "gencurrency")
@ -129,12 +139,12 @@ namespace NadekoBot.Modules.Games.Commands
int throwaway;
if (config.GenerateCurrencyChannels.TryRemove(e.Channel.Id, out throwaway))
{
await e.Channel.SendMessage("`Currency generation disabled on this channel.`");
await e.Channel.SendMessage("`Currency generation disabled on this channel.`").ConfigureAwait(false);
}
else
{
if (config.GenerateCurrencyChannels.TryAdd(e.Channel.Id, cd))
await e.Channel.SendMessage($"`Currency generation enabled on this channel. Cooldown is {cd} minutes.`");
await e.Channel.SendMessage($"`Currency generation enabled on this channel. Cooldown is {cd} minutes.`").ConfigureAwait(false);
}
});
}

View File

@ -15,11 +15,6 @@ namespace NadekoBot.Modules.Games.Commands
public static ConcurrentDictionary<Server, Poll> ActivePolls = new ConcurrentDictionary<Server, Poll>();
public Func<CommandEventArgs, Task> DoFunc()
{
throw new NotImplementedException();
}
internal override void Init(CommandGroupBuilder cgb)
{
cgb.CreateCommand(Module.Prefix + "poll")

View File

@ -13,7 +13,7 @@ namespace NadekoBot.Modules.Games.Commands.Trivia
{
internal class TriviaGame
{
private readonly object _guessLock = new object();
private readonly SemaphoreSlim _guessLock = new SemaphoreSlim(1,1);
private Server server { get; }
private Channel channel { get; }
@ -113,7 +113,8 @@ namespace NadekoBot.Modules.Games.Commands.Trivia
if (e.User.Id == NadekoBot.Client.CurrentUser.Id) return;
var guess = false;
lock (_guessLock)
await _guessLock.WaitAsync().ConfigureAwait(false);
try
{
if (GameActive && CurrentQuestion.IsAnswerCorrect(e.Message.Text) && !triviaCancelSource.IsCancellationRequested)
{
@ -122,6 +123,7 @@ namespace NadekoBot.Modules.Games.Commands.Trivia
guess = true;
}
}
finally { _guessLock.Release(); }
if (!guess) return;
triviaCancelSource.Cancel();
await channel.SendMessage($"☑️ {e.User.Mention} guessed it! The answer was: **{CurrentQuestion.Answer}**").ConfigureAwait(false);

View File

@ -36,7 +36,7 @@ namespace NadekoBot.Modules.Games
commands.ForEach(cmd => cmd.Init(cgb));
cgb.CreateCommand(Prefix + "choose")
.Description("Chooses a thing from a list of things | >choose Get up;Sleep;Sleep more")
.Description($"Chooses a thing from a list of things | `{Prefix}choose Get up;Sleep;Sleep more`")
.Parameter("list", ParameterType.Unparsed)
.Do(async e =>
{
@ -50,7 +50,7 @@ namespace NadekoBot.Modules.Games
});
cgb.CreateCommand(Prefix + "8ball")
.Description("Ask the 8ball a yes/no question.")
.Description($"Ask the 8ball a yes/no question. | `{Prefix}8ball should i do something`")
.Parameter("question", ParameterType.Unparsed)
.Do(async e =>
{
@ -67,7 +67,7 @@ namespace NadekoBot.Modules.Games
});
cgb.CreateCommand(Prefix + "rps")
.Description("Play a game of rocket paperclip scissors with Nadeko. | >rps scissors")
.Description($"Play a game of rocket paperclip scissors with Nadeko. | `{Prefix}rps scissors`")
.Parameter("input", ParameterType.Required)
.Do(async e =>
{

View File

@ -113,17 +113,10 @@ namespace NadekoBot.Modules.Music.Classes
if (CurrentSong == null)
continue;
try
{
OnStarted(this, CurrentSong);
await CurrentSong.Play(audioClient, cancelToken);
}
catch (OperationCanceledException)
{
Console.WriteLine("Song canceled");
SongCancelSource = new CancellationTokenSource();
cancelToken = SongCancelSource.Token;
}
OnCompleted(this, CurrentSong);
if (RepeatPlaylist)
@ -135,8 +128,14 @@ namespace NadekoBot.Modules.Music.Classes
}
finally
{
await Task.Delay(300).ConfigureAwait(false);
if (!cancelToken.IsCancellationRequested)
{
SongCancelSource.Cancel();
}
SongCancelSource = new CancellationTokenSource();
cancelToken = SongCancelSource.Token;
CurrentSong = null;
await Task.Delay(300).ConfigureAwait(false);
}
}
}

View File

@ -22,7 +22,7 @@ namespace NadekoBot.Modules.Music.Classes
public int BufferSize { get; }
private readonly object readWriteLock = new object();
private readonly SemaphoreSlim readWriteLock = new SemaphoreSlim(1, 1);
public PoopyBuffer(int size)
{
@ -32,12 +32,15 @@ namespace NadekoBot.Modules.Music.Classes
ringBuffer = new byte[size];
}
public int Read(byte[] buffer, int count)
public Task<int> ReadAsync(byte[] buffer, int count)
{
return Task.Run(async () =>
{
if (buffer.Length < count)
throw new ArgumentException();
//Console.WriteLine($"***\nRead: {ReadPosition}\nWrite: {WritePosition}\nContentLength:{ContentLength}\n***");
lock (readWriteLock)
await readWriteLock.WaitAsync().ConfigureAwait(false);
try
{
//read as much as you can if you're reading too much
if (count > ContentLength)
@ -77,6 +80,9 @@ namespace NadekoBot.Modules.Music.Classes
ReadPosition = readFromStart;
return count;
}
finally { readWriteLock.Release(); }
});
}
public async Task WriteAsync(byte[] buffer, int count, CancellationToken cancelToken)
@ -89,9 +95,12 @@ namespace NadekoBot.Modules.Music.Classes
if (cancelToken.IsCancellationRequested)
return;
}
await Task.Run(async () =>
{
//the while above assures that i cannot write past readposition with my write, so i don't have to check
// *unless its multithreaded or task is not awaited
lock (readWriteLock)
await readWriteLock.WaitAsync().ConfigureAwait(false);
try
{
// if i can just write without hitting buffer.length, do it
if (WritePosition + count < BufferSize)
@ -115,6 +124,8 @@ namespace NadekoBot.Modules.Music.Classes
WritePosition = wroteFromStart;
}
finally { readWriteLock.Release(); }
});
}
}
}

View File

@ -3,6 +3,7 @@ using NadekoBot.Classes;
using NadekoBot.Extensions;
using System;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
@ -31,9 +32,7 @@ namespace NadekoBot.Modules.Music.Classes
public SongInfo SongInfo { get; }
public string QueuerName { get; set; }
private PoopyBuffer songBuffer { get; set; }
private bool prebufferingComplete { get; set; } = false;
private bool bufferingCompleted { get; set; } = false;
public MusicPlayer MusicPlayer { get; set; }
public string PrettyCurrentTime()
@ -74,7 +73,7 @@ namespace NadekoBot.Modules.Music.Classes
return this;
}
private Task BufferSong(CancellationToken cancelToken) =>
private Task BufferSong(string filename, CancellationToken cancelToken) =>
Task.Factory.StartNew(async () =>
{
Process p = null;
@ -89,40 +88,38 @@ namespace NadekoBot.Modules.Music.Classes
RedirectStandardError = false,
CreateNoWindow = true,
});
const int blockSize = 3840;
var buffer = new byte[blockSize];
var attempt = 0;
while (!cancelToken.IsCancellationRequested)
var prebufferSize = 100ul.MiB();
using (var outStream = new FileStream(filename, FileMode.Append, FileAccess.Write, FileShare.Read))
{
var read = 0;
try
byte[] buffer = new byte[81920];
int bytesRead;
while ((bytesRead = await p.StandardOutput.BaseStream.ReadAsync(buffer, 0, buffer.Length, cancelToken).ConfigureAwait(false)) != 0)
{
read = await p.StandardOutput.BaseStream.ReadAsync(buffer, 0, blockSize, cancelToken)
.ConfigureAwait(false);
await outStream.WriteAsync(buffer, 0, bytesRead, cancelToken).ConfigureAwait(false);
while ((ulong)outStream.Length - bytesSent > prebufferSize)
await Task.Delay(100, cancelToken);
}
catch
{
return;
}
if (read == 0)
if (attempt++ == 50)
break;
else
await Task.Delay(100, cancelToken).ConfigureAwait(false);
else
attempt = 0;
await songBuffer.WriteAsync(buffer, read, cancelToken).ConfigureAwait(false);
if (songBuffer.ContentLength > 2.MB())
prebufferingComplete = true;
bufferingCompleted = true;
}
catch (System.ComponentModel.Win32Exception) {
var oldclr = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(@"You have not properly installed or configured FFMPEG.
Please install and configure FFMPEG to play music.
Check the guides for your platform on how to setup ffmpeg correctly:
Windows Guide: https://goo.gl/SCv72y
Linux Guide: https://goo.gl/rRhjCp");
Console.ForegroundColor = oldclr;
}
catch (Exception ex)
{
Console.WriteLine($"Buffering errored: {ex.Message}");
Console.WriteLine($"Buffering stopped: {ex.Message}");
}
finally
{
Console.WriteLine($"Buffering done." + $" [{songBuffer.ContentLength}]");
Console.WriteLine($"Buffering done.");
if (p != null)
{
try
@ -137,25 +134,41 @@ namespace NadekoBot.Modules.Music.Classes
internal async Task Play(IAudioClient voiceClient, CancellationToken cancelToken)
{
// initialize the buffer here because if this song was playing before (requeued), we must delete old buffer data
songBuffer = new PoopyBuffer(NadekoBot.Config.BufferSize);
var filename = Path.Combine(MusicModule.MusicDataPath, DateTime.Now.UnixTimestamp().ToString());
var bufferTask = BufferSong(cancelToken).ConfigureAwait(false);
var bufferAttempts = 0;
const int waitPerAttempt = 500;
var toAttemptTimes = SongInfo.ProviderType != MusicType.Normal ? 5 : 9;
while (!prebufferingComplete && bufferAttempts++ < toAttemptTimes)
var bufferTask = BufferSong(filename, cancelToken).ConfigureAwait(false);
var inStream = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Read, FileShare.Write);
bytesSent = 0;
try
{
await Task.Delay(waitPerAttempt, cancelToken).ConfigureAwait(false);
var prebufferingTask = CheckPrebufferingAsync(inStream, cancelToken);
var sw = new Stopwatch();
sw.Start();
var t = await Task.WhenAny(prebufferingTask, Task.Delay(5000, cancelToken));
if (t != prebufferingTask)
{
Console.WriteLine("Prebuffering timed out or canceled. Cannot get any data from the stream.");
return;
}
Console.WriteLine($"Prebuffering done? in {waitPerAttempt * bufferAttempts}");
else if(prebufferingTask.IsCanceled)
{
Console.WriteLine("Prebuffering timed out. Cannot get any data from the stream.");
return;
}
sw.Stop();
Console.WriteLine("Prebuffering successfully completed in "+ sw.Elapsed);
const int blockSize = 3840;
var attempt = 0;
byte[] buffer = new byte[blockSize];
while (!cancelToken.IsCancellationRequested)
{
//Console.WriteLine($"Read: {songBuffer.ReadPosition}\nWrite: {songBuffer.WritePosition}\nContentLength:{songBuffer.ContentLength}\n---------");
byte[] buffer = new byte[blockSize];
var read = songBuffer.Read(buffer, blockSize);
var read = inStream.Read(buffer, 0, buffer.Length);
//await inStream.CopyToAsync(voiceClient.OutputStream);
unchecked
{
bytesSent += (ulong)read;
@ -164,7 +177,6 @@ namespace NadekoBot.Modules.Music.Classes
if (attempt++ == 20)
{
voiceClient.Wait();
Console.WriteLine($"Song finished. [{songBuffer.ContentLength}]");
break;
}
else
@ -174,16 +186,30 @@ namespace NadekoBot.Modules.Music.Classes
while (this.MusicPlayer.Paused)
await Task.Delay(200, cancelToken).ConfigureAwait(false);
buffer = AdjustVolume(buffer, MusicPlayer.Volume);
voiceClient.Send(buffer, 0, read);
}
Console.WriteLine("Awiting buffer task");
}
finally
{
await bufferTask;
Console.WriteLine("Buffer task done.");
voiceClient.Clear();
cancelToken.ThrowIfCancellationRequested();
await Task.Run(() => voiceClient.Clear());
inStream.Dispose();
try { File.Delete(filename); } catch { }
}
}
private async Task CheckPrebufferingAsync(Stream inStream, CancellationToken cancelToken)
{
while (!bufferingCompleted && inStream.Length < 2.MiB())
{
await Task.Delay(100, cancelToken);
}
Console.WriteLine("Buffering successfull");
}
/*
//stackoverflow ftw
private static byte[] AdjustVolume(byte[] audioSamples, float volume)
{
@ -210,6 +236,33 @@ namespace NadekoBot.Modules.Music.Classes
}
return array;
}
*/
//aidiakapi ftw
public unsafe static byte[] AdjustVolume(byte[] audioSamples, float volume)
{
Contract.Requires(audioSamples != null);
Contract.Requires(audioSamples.Length % 2 == 0);
Contract.Requires(volume >= 0f && volume <= 1f);
Contract.Assert(BitConverter.IsLittleEndian);
if (Math.Abs(volume - 1f) < 0.0001f) return audioSamples;
// 16-bit precision for the multiplication
int volumeFixed = (int)Math.Round(volume * 65536d);
int count = audioSamples.Length / 2;
fixed (byte* srcBytes = audioSamples)
{
short* src = (short*)srcBytes;
for (int i = count; i != 0; i--, src++)
*src = (short)(((*src) * volumeFixed) >> 16);
}
return audioSamples;
}
public static async Task<Song> ResolveSong(string query, MusicType musicType = MusicType.Normal)
{

View File

@ -18,11 +18,16 @@ namespace NadekoBot.Modules.Music
{
internal class MusicModule : DiscordModule
{
public static ConcurrentDictionary<Server, MusicPlayer> MusicPlayers = new ConcurrentDictionary<Server, MusicPlayer>();
public const string MusicDataPath = "data/musicdata";
public MusicModule()
{
//it can fail if its currenctly opened or doesn't exist. Either way i don't care
try { Directory.Delete(MusicDataPath, true); } catch { }
Directory.CreateDirectory(MusicDataPath);
}
public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Music;
@ -713,7 +718,7 @@ namespace NadekoBot.Modules.Music
});
cgb.CreateCommand(Prefix + "goto")
.Description("Goes to a specific time in seconds in a song.")
.Description($"Goes to a specific time in seconds in a song. | {Prefix}goto 30")
.Parameter("time")
.Do(async e =>
{
@ -856,7 +861,7 @@ namespace NadekoBot.Modules.Music
}
if (!silent)
{
var queuedMessage = await textCh.SendMessage($"🎵`Queued`{resolvedSong.PrettyName} **at** `#{musicPlayer.Playlist.Count}`").ConfigureAwait(false);
var queuedMessage = await textCh.SendMessage($"🎵`Queued`{resolvedSong.PrettyName} **at** `#{musicPlayer.Playlist.Count + 1}`").ConfigureAwait(false);
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
Task.Run(async () =>
{

View File

@ -22,7 +22,7 @@ namespace NadekoBot.Modules.NSFW
cgb.AddCheck(PermissionChecker.Instance);
cgb.CreateCommand(Prefix + "hentai")
.Description("Shows a random NSFW hentai image from gelbooru and danbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~hentai yuri+kissing")
.Description($"Shows a random NSFW hentai image from gelbooru and danbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `{Prefix}hentai yuri+kissing`")
.Parameter("tag", ParameterType.Unparsed)
.Do(async e =>
{
@ -39,7 +39,7 @@ namespace NadekoBot.Modules.NSFW
await e.Channel.SendMessage("`No results.`");
});
cgb.CreateCommand(Prefix + "danbooru")
.Description("Shows a random hentai image from danbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~danbooru yuri+kissing")
.Description($"Shows a random hentai image from danbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `{Prefix}danbooru yuri+kissing`")
.Parameter("tag", ParameterType.Unparsed)
.Do(async e =>
{
@ -51,7 +51,7 @@ namespace NadekoBot.Modules.NSFW
await e.Channel.SendMessage(link).ConfigureAwait(false);
});
cgb.CreateCommand(Prefix + "gelbooru")
.Description("Shows a random hentai image from gelbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~gelbooru yuri+kissing")
.Description($"Shows a random hentai image from gelbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `{Prefix}gelbooru yuri+kissing`")
.Parameter("tag", ParameterType.Unparsed)
.Do(async e =>
{
@ -64,7 +64,7 @@ namespace NadekoBot.Modules.NSFW
});
cgb.CreateCommand(Prefix + "rule34")
.Description("Shows a random image from rule34.xx with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~rule34 yuri+kissing")
.Description($"Shows a random image from rule34.xx with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `{Prefix}rule34 yuri+kissing`")
.Parameter("tag", ParameterType.Unparsed)
.Do(async e =>
{
@ -76,7 +76,7 @@ namespace NadekoBot.Modules.NSFW
await e.Channel.SendMessage(link).ConfigureAwait(false);
});
cgb.CreateCommand(Prefix + "e621")
.Description("Shows a random hentai image from e621.net with a given tag. Tag is optional but preffered. Use spaces for multiple tags. | ~e621 yuri kissing")
.Description($"Shows a random hentai image from e621.net with a given tag. Tag is optional but preffered. Use spaces for multiple tags. | `{Prefix}e621 yuri kissing`")
.Parameter("tag", ParameterType.Unparsed)
.Do(async e =>
{

View File

@ -150,21 +150,21 @@ namespace NadekoBot.Modules.Permissions.Classes
return PermissionBanType.None;
}
private static void WriteServerToJson(ServerPermissions serverPerms)
private static Task WriteServerToJson(ServerPermissions serverPerms) => Task.Run(() =>
{
string pathToFile = $"data/permissions/{serverPerms.Id}.json";
File.WriteAllText(pathToFile,
Newtonsoft.Json.JsonConvert.SerializeObject(serverPerms, Newtonsoft.Json.Formatting.Indented));
}
});
public static void WriteToJson()
public static Task WriteToJson() => Task.Run(() =>
{
Directory.CreateDirectory("data/permissions/");
foreach (var kvp in PermissionsDict)
{
WriteServerToJson(kvp.Value);
}
}
});
public static string GetServerPermissionsRoleName(Server server)
{
@ -174,25 +174,25 @@ namespace NadekoBot.Modules.Permissions.Classes
return serverPerms.PermissionsControllerRole;
}
internal static void SetPermissionsRole(Server server, string roleName)
internal static async Task SetPermissionsRole(Server server, string roleName)
{
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
new ServerPermissions(server.Id, server.Name));
serverPerms.PermissionsControllerRole = roleName;
Task.Run(() => WriteServerToJson(serverPerms));
await WriteServerToJson(serverPerms).ConfigureAwait(false);
}
internal static void SetVerbosity(Server server, bool val)
internal static async Task SetVerbosity(Server server, bool val)
{
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
new ServerPermissions(server.Id, server.Name));
serverPerms.Verbose = val;
Task.Run(() => WriteServerToJson(serverPerms));
await WriteServerToJson(serverPerms).ConfigureAwait(false);
}
internal static void CopyRolePermissions(Role fromRole, Role toRole)
internal static async Task CopyRolePermissions(Role fromRole, Role toRole)
{
var server = fromRole.Server;
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
@ -207,10 +207,10 @@ namespace NadekoBot.Modules.Permissions.Classes
to.CopyFrom(from);
Task.Run(() => WriteServerToJson(serverPerms));
await WriteServerToJson(serverPerms).ConfigureAwait(false);
}
internal static void CopyChannelPermissions(Channel fromChannel, Channel toChannel)
internal static async Task CopyChannelPermissions(Channel fromChannel, Channel toChannel)
{
var server = fromChannel.Server;
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
@ -225,10 +225,10 @@ namespace NadekoBot.Modules.Permissions.Classes
to.CopyFrom(from);
Task.Run(() => WriteServerToJson(serverPerms));
await WriteServerToJson(serverPerms).ConfigureAwait(false);
}
internal static void CopyUserPermissions(User fromUser, User toUser)
internal static async Task CopyUserPermissions(User fromUser, User toUser)
{
var server = fromUser.Server;
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
@ -243,10 +243,10 @@ namespace NadekoBot.Modules.Permissions.Classes
to.CopyFrom(from);
Task.Run(() => WriteServerToJson(serverPerms));
await WriteServerToJson(serverPerms).ConfigureAwait(false);
}
public static void SetServerModulePermission(Server server, string moduleName, bool value)
public static async Task SetServerModulePermission(Server server, string moduleName, bool value)
{
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
new ServerPermissions(server.Id, server.Name));
@ -256,10 +256,10 @@ namespace NadekoBot.Modules.Permissions.Classes
modules[moduleName] = value;
else
modules.TryAdd(moduleName, value);
Task.Run(() => WriteServerToJson(serverPerms));
await WriteServerToJson(serverPerms).ConfigureAwait(false);
}
public static void SetServerCommandPermission(Server server, string commandName, bool value)
public static async Task SetServerCommandPermission(Server server, string commandName, bool value)
{
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
new ServerPermissions(server.Id, server.Name));
@ -269,10 +269,10 @@ namespace NadekoBot.Modules.Permissions.Classes
commands[commandName] = value;
else
commands.TryAdd(commandName, value);
Task.Run(() => WriteServerToJson(serverPerms));
await WriteServerToJson(serverPerms).ConfigureAwait(false);
}
public static void SetChannelModulePermission(Channel channel, string moduleName, bool value)
public static async Task SetChannelModulePermission(Channel channel, string moduleName, bool value)
{
var server = channel.Server;
@ -288,10 +288,10 @@ namespace NadekoBot.Modules.Permissions.Classes
modules[moduleName] = value;
else
modules.TryAdd(moduleName, value);
Task.Run(() => WriteServerToJson(serverPerms));
await WriteServerToJson(serverPerms).ConfigureAwait(false);
}
public static void SetChannelCommandPermission(Channel channel, string commandName, bool value)
public static async Task SetChannelCommandPermission(Channel channel, string commandName, bool value)
{
var server = channel.Server;
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
@ -306,10 +306,10 @@ namespace NadekoBot.Modules.Permissions.Classes
commands[commandName] = value;
else
commands.TryAdd(commandName, value);
Task.Run(() => WriteServerToJson(serverPerms));
await WriteServerToJson(serverPerms).ConfigureAwait(false);
}
public static void SetRoleModulePermission(Role role, string moduleName, bool value)
public static async Task SetRoleModulePermission(Role role, string moduleName, bool value)
{
var server = role.Server;
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
@ -324,10 +324,10 @@ namespace NadekoBot.Modules.Permissions.Classes
modules[moduleName] = value;
else
modules.TryAdd(moduleName, value);
Task.Run(() => WriteServerToJson(serverPerms));
await WriteServerToJson(serverPerms).ConfigureAwait(false);
}
public static void SetRoleCommandPermission(Role role, string commandName, bool value)
public static async Task SetRoleCommandPermission(Role role, string commandName, bool value)
{
var server = role.Server;
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
@ -342,10 +342,10 @@ namespace NadekoBot.Modules.Permissions.Classes
commands[commandName] = value;
else
commands.TryAdd(commandName, value);
Task.Run(() => WriteServerToJson(serverPerms));
await WriteServerToJson(serverPerms).ConfigureAwait(false);
}
public static void SetUserModulePermission(User user, string moduleName, bool value)
public static async Task SetUserModulePermission(User user, string moduleName, bool value)
{
var server = user.Server;
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
@ -360,10 +360,10 @@ namespace NadekoBot.Modules.Permissions.Classes
modules[moduleName] = value;
else
modules.TryAdd(moduleName, value);
Task.Run(() => WriteServerToJson(serverPerms));
await WriteServerToJson(serverPerms).ConfigureAwait(false);
}
public static void SetUserCommandPermission(User user, string commandName, bool value)
public static async Task SetUserCommandPermission(User user, string commandName, bool value)
{
var server = user.Server;
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
@ -377,19 +377,19 @@ namespace NadekoBot.Modules.Permissions.Classes
commands[commandName] = value;
else
commands.TryAdd(commandName, value);
Task.Run(() => WriteServerToJson(serverPerms));
await WriteServerToJson(serverPerms).ConfigureAwait(false);
}
public static void SetServerWordPermission(Server server, bool value)
public static async Task SetServerWordPermission(Server server, bool value)
{
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
new ServerPermissions(server.Id, server.Name));
serverPerms.Permissions.FilterWords = value;
Task.Run(() => WriteServerToJson(serverPerms));
await WriteServerToJson(serverPerms).ConfigureAwait(false);
}
public static void SetChannelWordPermission(Channel channel, bool value)
public static async Task SetChannelWordPermission(Channel channel, bool value)
{
var server = channel.Server;
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
@ -399,19 +399,19 @@ namespace NadekoBot.Modules.Permissions.Classes
serverPerms.ChannelPermissions.Add(channel.Id, new Permissions(channel.Name));
serverPerms.ChannelPermissions[channel.Id].FilterWords = value;
Task.Run(() => WriteServerToJson(serverPerms));
await WriteServerToJson(serverPerms).ConfigureAwait(false);
}
public static void SetServerFilterInvitesPermission(Server server, bool value)
public static async Task SetServerFilterInvitesPermission(Server server, bool value)
{
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
new ServerPermissions(server.Id, server.Name));
serverPerms.Permissions.FilterInvites = value;
Task.Run(() => WriteServerToJson(serverPerms));
await WriteServerToJson(serverPerms).ConfigureAwait(false);
}
public static void SetChannelFilterInvitesPermission(Channel channel, bool value)
public static async Task SetChannelFilterInvitesPermission(Channel channel, bool value)
{
var server = channel.Server;
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
@ -421,10 +421,10 @@ namespace NadekoBot.Modules.Permissions.Classes
serverPerms.ChannelPermissions.Add(channel.Id, new Permissions(channel.Name));
serverPerms.ChannelPermissions[channel.Id].FilterInvites = value;
Task.Run(() => WriteServerToJson(serverPerms));
await WriteServerToJson(serverPerms).ConfigureAwait(false);
}
public static void SetCommandCooldown(Server server, string commandName, int value)
public static async Task SetCommandCooldown(Server server, string commandName, int value)
{
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
new ServerPermissions(server.Id, server.Name));
@ -436,26 +436,26 @@ namespace NadekoBot.Modules.Permissions.Classes
serverPerms.CommandCooldowns.AddOrUpdate(commandName, value, (str, v) => value);
}
Task.Run(() => WriteServerToJson(serverPerms));
await WriteServerToJson(serverPerms).ConfigureAwait(false);
}
public static void AddFilteredWord(Server server, string word)
public static async Task AddFilteredWord(Server server, string word)
{
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
new ServerPermissions(server.Id, server.Name));
if (serverPerms.Words.Contains(word))
throw new InvalidOperationException("That word is already banned.");
serverPerms.Words.Add(word);
Task.Run(() => WriteServerToJson(serverPerms));
await WriteServerToJson(serverPerms).ConfigureAwait(false);
}
public static void RemoveFilteredWord(Server server, string word)
public static async Task RemoveFilteredWord(Server server, string word)
{
var serverPerms = PermissionsDict.GetOrAdd(server.Id,
new ServerPermissions(server.Id, server.Name));
if (!serverPerms.Words.Contains(word))
throw new InvalidOperationException("That word is not banned.");
serverPerms.Words.Remove(word);
Task.Run(() => WriteServerToJson(serverPerms));
await WriteServerToJson(serverPerms).ConfigureAwait(false);
}
}
/// <summary>

View File

@ -71,7 +71,7 @@ namespace NadekoBot.Modules.Permissions.Commands
var chan = string.IsNullOrWhiteSpace(chanStr)
? e.Channel
: PermissionHelper.ValidateChannel(e.Server, chanStr);
PermissionsHandler.SetChannelFilterInvitesPermission(chan, state);
await PermissionsHandler.SetChannelFilterInvitesPermission(chan, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Invite Filter has been **{(state ? "enabled" : "disabled")}** for **{chan.Name}** channel.")
.ConfigureAwait(false);
return;
@ -80,7 +80,7 @@ namespace NadekoBot.Modules.Permissions.Commands
foreach (var curChannel in e.Server.TextChannels)
{
PermissionsHandler.SetChannelFilterInvitesPermission(curChannel, state);
await PermissionsHandler.SetChannelFilterInvitesPermission(curChannel, state).ConfigureAwait(false);
}
await e.Channel.SendMessage($"Invite Filter has been **{(state ? "enabled" : "disabled")}** for **ALL** channels.")
.ConfigureAwait(false);
@ -102,7 +102,7 @@ namespace NadekoBot.Modules.Permissions.Commands
try
{
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
PermissionsHandler.SetServerFilterInvitesPermission(e.Server, state);
await PermissionsHandler.SetServerFilterInvitesPermission(e.Server, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Invite Filter has been **{(state ? "enabled" : "disabled")}** for this server.")
.ConfigureAwait(false);

View File

@ -68,7 +68,7 @@ namespace NadekoBot.Modules.Permissions.Commands
var chan = string.IsNullOrWhiteSpace(chanStr)
? e.Channel
: PermissionHelper.ValidateChannel(e.Server, chanStr);
PermissionsHandler.SetChannelWordPermission(chan, state);
await PermissionsHandler.SetChannelWordPermission(chan, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Word filtering has been **{(state ? "enabled" : "disabled")}** for **{chan.Name}** channel.").ConfigureAwait(false);
return;
}
@ -76,7 +76,7 @@ namespace NadekoBot.Modules.Permissions.Commands
foreach (var curChannel in e.Server.TextChannels)
{
PermissionsHandler.SetChannelWordPermission(curChannel, state);
await PermissionsHandler.SetChannelWordPermission(curChannel, state).ConfigureAwait(false);
}
await e.Channel.SendMessage($"Word filtering has been **{(state ? "enabled" : "disabled")}** for **ALL** channels.").ConfigureAwait(false);
}
@ -98,7 +98,7 @@ namespace NadekoBot.Modules.Permissions.Commands
var word = e.GetArg("word");
if (string.IsNullOrWhiteSpace(word))
return;
PermissionsHandler.AddFilteredWord(e.Server, word.ToLowerInvariant().Trim());
await PermissionsHandler.AddFilteredWord(e.Server, word.ToLowerInvariant().Trim()).ConfigureAwait(false);
await e.Channel.SendMessage($"Successfully added new filtered word.").ConfigureAwait(false);
}
@ -120,7 +120,7 @@ namespace NadekoBot.Modules.Permissions.Commands
var word = e.GetArg("word");
if (string.IsNullOrWhiteSpace(word))
return;
PermissionsHandler.RemoveFilteredWord(e.Server, word.ToLowerInvariant().Trim());
await PermissionsHandler.RemoveFilteredWord(e.Server, word.ToLowerInvariant().Trim()).ConfigureAwait(false);
await e.Channel.SendMessage($"Successfully removed filtered word.").ConfigureAwait(false);
}
@ -159,7 +159,7 @@ namespace NadekoBot.Modules.Permissions.Commands
try
{
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
PermissionsHandler.SetServerWordPermission(e.Server, state);
await PermissionsHandler.SetServerWordPermission(e.Server, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Word filtering has been **{(state ? "enabled" : "disabled")}** on this server.")
.ConfigureAwait(false);

View File

@ -55,7 +55,7 @@ namespace NadekoBot.Modules.Permissions
await e.Channel.SendMessage($"Role `{arg}` probably doesn't exist. Create the role with that name first.").ConfigureAwait(false);
return;
}
PermissionsHandler.SetPermissionsRole(e.Server, role.Name);
await PermissionsHandler.SetPermissionsRole(e.Server, role.Name).ConfigureAwait(false);
await e.Channel.SendMessage($"Role `{role.Name}` is now required in order to change permissions.").ConfigureAwait(false);
});
@ -71,7 +71,7 @@ namespace NadekoBot.Modules.Permissions
var args = arg.Split('~').Select(a => a.Trim()).ToArray();
if (args.Length > 2)
{
await e.Channel.SendMessage("💢Invalid number of '~'s in the argument.");
await e.Channel.SendMessage("💢Invalid number of '~'s in the argument.").ConfigureAwait(false);
return;
}
try
@ -79,12 +79,12 @@ namespace NadekoBot.Modules.Permissions
var fromRole = PermissionHelper.ValidateRole(e.Server, args[0]);
var toRole = PermissionHelper.ValidateRole(e.Server, args[1]);
PermissionsHandler.CopyRolePermissions(fromRole, toRole);
await e.Channel.SendMessage($"Copied permission settings from **{fromRole.Name}** to **{toRole.Name}**.");
await PermissionsHandler.CopyRolePermissions(fromRole, toRole).ConfigureAwait(false);
await e.Channel.SendMessage($"Copied permission settings from **{fromRole.Name}** to **{toRole.Name}**.").ConfigureAwait(false);
}
catch (Exception ex)
{
await e.Channel.SendMessage($"💢{ex.Message}");
await e.Channel.SendMessage($"💢{ex.Message}").ConfigureAwait(false);
}
});
cgb.CreateCommand(Prefix + "chnlpermscopy")
@ -107,8 +107,8 @@ namespace NadekoBot.Modules.Permissions
var fromChannel = PermissionHelper.ValidateChannel(e.Server, args[0]);
var toChannel = PermissionHelper.ValidateChannel(e.Server, args[1]);
PermissionsHandler.CopyChannelPermissions(fromChannel, toChannel);
await e.Channel.SendMessage($"Copied permission settings from **{fromChannel.Name}** to **{toChannel.Name}**.");
await PermissionsHandler.CopyChannelPermissions(fromChannel, toChannel).ConfigureAwait(false);
await e.Channel.SendMessage($"Copied permission settings from **{fromChannel.Name}** to **{toChannel.Name}**.").ConfigureAwait(false);
}
catch (Exception ex)
{
@ -127,7 +127,7 @@ namespace NadekoBot.Modules.Permissions
var args = arg.Split('~').Select(a => a.Trim()).ToArray();
if (args.Length > 2)
{
await e.Channel.SendMessage("💢Invalid number of '~'s in the argument.");
await e.Channel.SendMessage("💢Invalid number of '~'s in the argument.").ConfigureAwait(false);
return;
}
try
@ -135,8 +135,8 @@ namespace NadekoBot.Modules.Permissions
var fromUser = PermissionHelper.ValidateUser(e.Server, args[0]);
var toUser = PermissionHelper.ValidateUser(e.Server, args[1]);
PermissionsHandler.CopyUserPermissions(fromUser, toUser);
await e.Channel.SendMessage($"Copied permission settings from **{fromUser.ToString()}**to * *{toUser.ToString()}**.");
await PermissionsHandler.CopyUserPermissions(fromUser, toUser).ConfigureAwait(false);
await e.Channel.SendMessage($"Copied permission settings from **{fromUser.ToString()}**to * *{toUser.ToString()}**.").ConfigureAwait(false);
}
catch (Exception ex)
{
@ -146,13 +146,13 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "verbose")
.Alias(Prefix + "v")
.Description("Sets whether to show when a command/module is blocked. | ;verbose true")
.Description($"Sets whether to show when a command/module is blocked. | `{Prefix}verbose true`")
.Parameter("arg", ParameterType.Required)
.Do(async e =>
{
var arg = e.GetArg("arg");
var val = PermissionHelper.ValidateBool(arg);
PermissionsHandler.SetVerbosity(e.Server, val);
await PermissionsHandler.SetVerbosity(e.Server, val).ConfigureAwait(false);
await e.Channel.SendMessage($"Verbosity set to {val}.").ConfigureAwait(false);
});
@ -169,7 +169,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "roleperms")
.Alias(Prefix + "rp")
.Description("Shows banned permissions for a certain role. No argument means for everyone. | ;rp AwesomeRole")
.Description($"Shows banned permissions for a certain role. No argument means for everyone. | `{Prefix}rp AwesomeRole`")
.Parameter("role", ParameterType.Unparsed)
.Do(async e =>
{
@ -195,7 +195,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "chnlperms")
.Alias(Prefix + "cp")
.Description("Shows banned permissions for a certain channel. No argument means for this channel. | ;cp #dev")
.Description($"Shows banned permissions for a certain channel. No argument means for this channel. | `{Prefix}cp #dev`")
.Parameter("channel", ParameterType.Unparsed)
.Do(async e =>
{
@ -220,7 +220,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "userperms")
.Alias(Prefix + "up")
.Description("Shows banned permissions for a certain user. No argument means for yourself. | ;up Kwoth")
.Description($"Shows banned permissions for a certain user. No argument means for yourself. | `{Prefix}up Kwoth`")
.Parameter("user", ParameterType.Unparsed)
.Do(async e =>
{
@ -246,7 +246,7 @@ namespace NadekoBot.Modules.Permissions
.Alias(Prefix + "sm")
.Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required)
.Description("Sets a module's permission at the server level. | ;sm \"module name\" enable")
.Description($"Sets a module's permission at the server level. | `{Prefix}sm \"module name\" enable`")
.Do(async e =>
{
try
@ -254,7 +254,7 @@ namespace NadekoBot.Modules.Permissions
var module = PermissionHelper.ValidateModule(e.GetArg("module"));
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
PermissionsHandler.SetServerModulePermission(e.Server, module, state);
await PermissionsHandler.SetServerModulePermission(e.Server, module, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** on this server.").ConfigureAwait(false);
}
catch (ArgumentException exArg)
@ -270,7 +270,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "srvrcmd").Alias(Prefix + "sc")
.Parameter("command", ParameterType.Required)
.Parameter("bool", ParameterType.Required)
.Description("Sets a command's permission at the server level. | ;sc \"command name\" disable")
.Description($"Sets a command's permission at the server level. | `{Prefix}sc \"command name\" disable`")
.Do(async e =>
{
try
@ -278,7 +278,7 @@ namespace NadekoBot.Modules.Permissions
var command = PermissionHelper.ValidateCommand(e.GetArg("command"));
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
PermissionsHandler.SetServerCommandPermission(e.Server, command, state);
await PermissionsHandler.SetServerCommandPermission(e.Server, command, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Command **{command}** has been **{(state ? "enabled" : "disabled")}** on this server.").ConfigureAwait(false);
}
catch (ArgumentException exArg)
@ -295,7 +295,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required)
.Parameter("role", ParameterType.Unparsed)
.Description("Sets a module's permission at the role level. | ;rm \"module name\" enable MyRole")
.Description($"Sets a module's permission at the role level. | `{Prefix}rm \"module name\" enable MyRole`")
.Do(async e =>
{
try
@ -307,7 +307,7 @@ namespace NadekoBot.Modules.Permissions
{
foreach (var role in e.Server.Roles)
{
PermissionsHandler.SetRoleModulePermission(role, module, state);
await PermissionsHandler.SetRoleModulePermission(role, module, state).ConfigureAwait(false);
}
await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** for **ALL** roles.").ConfigureAwait(false);
}
@ -315,7 +315,7 @@ namespace NadekoBot.Modules.Permissions
{
var role = PermissionHelper.ValidateRole(e.Server, e.GetArg("role"));
PermissionsHandler.SetRoleModulePermission(role, module, state);
await PermissionsHandler.SetRoleModulePermission(role, module, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** for **{role.Name}** role.").ConfigureAwait(false);
}
}
@ -333,7 +333,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("command", ParameterType.Required)
.Parameter("bool", ParameterType.Required)
.Parameter("role", ParameterType.Unparsed)
.Description("Sets a command's permission at the role level. | ;rc \"command name\" disable MyRole")
.Description($"Sets a command's permission at the role level. | `{Prefix}rc \"command name\" disable MyRole`")
.Do(async e =>
{
try
@ -345,7 +345,7 @@ namespace NadekoBot.Modules.Permissions
{
foreach (var role in e.Server.Roles)
{
PermissionsHandler.SetRoleCommandPermission(role, command, state);
await PermissionsHandler.SetRoleCommandPermission(role, command, state).ConfigureAwait(false);
}
await e.Channel.SendMessage($"Command **{command}** has been **{(state ? "enabled" : "disabled")}** for **ALL** roles.").ConfigureAwait(false);
}
@ -353,7 +353,7 @@ namespace NadekoBot.Modules.Permissions
{
var role = PermissionHelper.ValidateRole(e.Server, e.GetArg("role"));
PermissionsHandler.SetRoleCommandPermission(role, command, state);
await PermissionsHandler.SetRoleCommandPermission(role, command, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Command **{command}** has been **{(state ? "enabled" : "disabled")}** for **{role.Name}** role.").ConfigureAwait(false);
}
}
@ -371,7 +371,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required)
.Parameter("channel", ParameterType.Unparsed)
.Description("Sets a module's permission at the channel level. | ;cm \"module name\" enable SomeChannel")
.Description($"Sets a module's permission at the channel level. | `{Prefix}cm \"module name\" enable SomeChannel`")
.Do(async e =>
{
try
@ -383,20 +383,20 @@ namespace NadekoBot.Modules.Permissions
{
foreach (var channel in e.Server.TextChannels)
{
PermissionsHandler.SetChannelModulePermission(channel, module, state);
await PermissionsHandler.SetChannelModulePermission(channel, module, state).ConfigureAwait(false);
}
await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** on **ALL** channels.").ConfigureAwait(false);
}
else if (string.IsNullOrWhiteSpace(channelArg))
{
PermissionsHandler.SetChannelModulePermission(e.Channel, module, state);
await PermissionsHandler.SetChannelModulePermission(e.Channel, module, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** for **{e.Channel.Name}** channel.").ConfigureAwait(false);
}
else
{
var channel = PermissionHelper.ValidateChannel(e.Server, channelArg);
PermissionsHandler.SetChannelModulePermission(channel, module, state);
await PermissionsHandler.SetChannelModulePermission(channel, module, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** for **{channel.Name}** channel.").ConfigureAwait(false);
}
}
@ -414,7 +414,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("command", ParameterType.Required)
.Parameter("bool", ParameterType.Required)
.Parameter("channel", ParameterType.Unparsed)
.Description("Sets a command's permission at the channel level. | ;cc \"command name\" enable SomeChannel")
.Description($"Sets a command's permission at the channel level. | `{Prefix}cc \"command name\" enable SomeChannel`")
.Do(async e =>
{
try
@ -426,7 +426,7 @@ namespace NadekoBot.Modules.Permissions
{
foreach (var channel in e.Server.TextChannels)
{
PermissionsHandler.SetChannelCommandPermission(channel, command, state);
await PermissionsHandler.SetChannelCommandPermission(channel, command, state).ConfigureAwait(false);
}
await e.Channel.SendMessage($"Command **{command}** has been **{(state ? "enabled" : "disabled")}** on **ALL** channels.").ConfigureAwait(false);
}
@ -434,7 +434,7 @@ namespace NadekoBot.Modules.Permissions
{
var channel = PermissionHelper.ValidateChannel(e.Server, e.GetArg("channel"));
PermissionsHandler.SetChannelCommandPermission(channel, command, state);
await PermissionsHandler.SetChannelCommandPermission(channel, command, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Command **{command}** has been **{(state ? "enabled" : "disabled")}** for **{channel.Name}** channel.").ConfigureAwait(false);
}
}
@ -452,7 +452,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required)
.Parameter("user", ParameterType.Unparsed)
.Description("Sets a module's permission at the user level. | ;um \"module name\" enable SomeUsername")
.Description($"Sets a module's permission at the user level. | `{Prefix}um \"module name\" enable SomeUsername`")
.Do(async e =>
{
try
@ -461,7 +461,7 @@ namespace NadekoBot.Modules.Permissions
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
var user = PermissionHelper.ValidateUser(e.Server, e.GetArg("user"));
PermissionsHandler.SetUserModulePermission(user, module, state);
await PermissionsHandler.SetUserModulePermission(user, module, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Module **{module}** has been **{(state ? "enabled" : "disabled")}** for user **{user.Name}**.").ConfigureAwait(false);
}
catch (ArgumentException exArg)
@ -478,7 +478,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("command", ParameterType.Required)
.Parameter("bool", ParameterType.Required)
.Parameter("user", ParameterType.Unparsed)
.Description("Sets a command's permission at the user level. | ;uc \"command name\" enable SomeUsername")
.Description($"Sets a command's permission at the user level. | `{Prefix}uc \"command name\" enable SomeUsername`")
.Do(async e =>
{
try
@ -487,7 +487,7 @@ namespace NadekoBot.Modules.Permissions
var state = PermissionHelper.ValidateBool(e.GetArg("bool"));
var user = PermissionHelper.ValidateUser(e.Server, e.GetArg("user"));
PermissionsHandler.SetUserCommandPermission(user, command, state);
await PermissionsHandler.SetUserCommandPermission(user, command, state).ConfigureAwait(false);
await e.Channel.SendMessage($"Command **{command}** has been **{(state ? "enabled" : "disabled")}** for user **{user.Name}**.").ConfigureAwait(false);
}
catch (ArgumentException exArg)
@ -502,7 +502,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "allsrvrmdls").Alias(Prefix + "asm")
.Parameter("bool", ParameterType.Required)
.Description("Sets permissions for all modules at the server level. | ;asm [enable/disable]")
.Description($"Sets permissions for all modules at the server level. | `{Prefix}asm [enable/disable]`")
.Do(async e =>
{
try
@ -511,7 +511,7 @@ namespace NadekoBot.Modules.Permissions
foreach (var module in NadekoBot.Client.GetService<ModuleService>().Modules)
{
PermissionsHandler.SetServerModulePermission(e.Server, module.Name, state);
await PermissionsHandler.SetServerModulePermission(e.Server, module.Name, state).ConfigureAwait(false);
}
await e.Channel.SendMessage($"All modules have been **{(state ? "enabled" : "disabled")}** on this server.").ConfigureAwait(false);
}
@ -528,7 +528,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "allsrvrcmds").Alias(Prefix + "asc")
.Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required)
.Description("Sets permissions for all commands from a certain module at the server level. | ;asc \"module name\" [enable/disable]")
.Description($"Sets permissions for all commands from a certain module at the server level. | `{Prefix}asc \"module name\" [enable/disable]`")
.Do(async e =>
{
try
@ -538,7 +538,7 @@ namespace NadekoBot.Modules.Permissions
foreach (var command in NadekoBot.Client.GetService<CommandService>().AllCommands.Where(c => c.Category == module))
{
PermissionsHandler.SetServerCommandPermission(e.Server, command.Text, state);
await PermissionsHandler.SetServerCommandPermission(e.Server, command.Text, state).ConfigureAwait(false);
}
await e.Channel.SendMessage($"All commands from the **{module}** module have been **{(state ? "enabled" : "disabled")}** on this server.").ConfigureAwait(false);
}
@ -555,7 +555,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "allchnlmdls").Alias(Prefix + "acm")
.Parameter("bool", ParameterType.Required)
.Parameter("channel", ParameterType.Unparsed)
.Description("Sets permissions for all modules at the channel level. | ;acm [enable/disable] SomeChannel")
.Description($"Sets permissions for all modules at the channel level. | `{Prefix}acm [enable/disable] SomeChannel`")
.Do(async e =>
{
try
@ -565,7 +565,7 @@ namespace NadekoBot.Modules.Permissions
var channel = string.IsNullOrWhiteSpace(chArg) ? e.Channel : PermissionHelper.ValidateChannel(e.Server, chArg);
foreach (var module in NadekoBot.Client.GetService<ModuleService>().Modules)
{
PermissionsHandler.SetChannelModulePermission(channel, module.Name, state);
await PermissionsHandler.SetChannelModulePermission(channel, module.Name, state).ConfigureAwait(false);
}
await e.Channel.SendMessage($"All modules have been **{(state ? "enabled" : "disabled")}** for **{channel.Name}** channel.").ConfigureAwait(false);
@ -584,7 +584,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required)
.Parameter("channel", ParameterType.Unparsed)
.Description("Sets permissions for all commands from a certain module at the channel level. | ;acc \"module name\" [enable/disable] SomeChannel")
.Description($"Sets permissions for all commands from a certain module at the channel level. | `{Prefix}acc \"module name\" [enable/disable] SomeChannel`")
.Do(async e =>
{
try
@ -594,7 +594,7 @@ namespace NadekoBot.Modules.Permissions
var channel = PermissionHelper.ValidateChannel(e.Server, e.GetArg("channel"));
foreach (var command in NadekoBot.Client.GetService<CommandService>().AllCommands.Where(c => c.Category == module))
{
PermissionsHandler.SetChannelCommandPermission(channel, command.Text, state);
await PermissionsHandler.SetChannelCommandPermission(channel, command.Text, state).ConfigureAwait(false);
}
await e.Channel.SendMessage($"All commands from the **{module}** module have been **{(state ? "enabled" : "disabled")}** for **{channel.Name}** channel.").ConfigureAwait(false);
}
@ -611,7 +611,7 @@ namespace NadekoBot.Modules.Permissions
cgb.CreateCommand(Prefix + "allrolemdls").Alias(Prefix + "arm")
.Parameter("bool", ParameterType.Required)
.Parameter("role", ParameterType.Unparsed)
.Description("Sets permissions for all modules at the role level. | ;arm [enable/disable] MyRole")
.Description($"Sets permissions for all modules at the role level. | `{Prefix}arm [enable/disable] MyRole`")
.Do(async e =>
{
try
@ -620,7 +620,7 @@ namespace NadekoBot.Modules.Permissions
var role = PermissionHelper.ValidateRole(e.Server, e.GetArg("role"));
foreach (var module in NadekoBot.Client.GetService<ModuleService>().Modules)
{
PermissionsHandler.SetRoleModulePermission(role, module.Name, state);
await PermissionsHandler.SetRoleModulePermission(role, module.Name, state).ConfigureAwait(false);
}
await e.Channel.SendMessage($"All modules have been **{(state ? "enabled" : "disabled")}** for **{role.Name}** role.").ConfigureAwait(false);
@ -639,7 +639,7 @@ namespace NadekoBot.Modules.Permissions
.Parameter("module", ParameterType.Required)
.Parameter("bool", ParameterType.Required)
.Parameter("role", ParameterType.Unparsed)
.Description("Sets permissions for all commands from a certain module at the role level. | ;arc \"module name\" [enable/disable] MyRole")
.Description($"Sets permissions for all commands from a certain module at the role level. | `{Prefix}arc \"module name\" [enable/disable] MyRole`")
.Do(async e =>
{
try
@ -652,7 +652,7 @@ namespace NadekoBot.Modules.Permissions
{
foreach (var command in NadekoBot.Client.GetService<CommandService>().AllCommands.Where(c => c.Category == module))
{
PermissionsHandler.SetRoleCommandPermission(role, command.Text, state);
await PermissionsHandler.SetRoleCommandPermission(role, command.Text, state).ConfigureAwait(false);
}
}
await e.Channel.SendMessage($"All commands from the **{module}** module have been **{(state ? "enabled" : "disabled")}** for **all roles** role.").ConfigureAwait(false);
@ -663,7 +663,7 @@ namespace NadekoBot.Modules.Permissions
foreach (var command in NadekoBot.Client.GetService<CommandService>().AllCommands.Where(c => c.Category == module))
{
PermissionsHandler.SetRoleCommandPermission(role, command.Text, state);
await PermissionsHandler.SetRoleCommandPermission(role, command.Text, state).ConfigureAwait(false);
}
await e.Channel.SendMessage($"All commands from the **{module}** module have been **{(state ? "enabled" : "disabled")}** for **{role.Name}** role.").ConfigureAwait(false);
}
@ -679,7 +679,7 @@ namespace NadekoBot.Modules.Permissions
});
cgb.CreateCommand(Prefix + "ubl")
.Description("Blacklists a mentioned user. | ;ubl [user_mention]")
.Description($"Blacklists a mentioned user. | `{Prefix}ubl [user_mention]`")
.Parameter("user", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>
@ -689,13 +689,13 @@ namespace NadekoBot.Modules.Permissions
if (!e.Message.MentionedUsers.Any()) return;
var usr = e.Message.MentionedUsers.First();
NadekoBot.Config.UserBlacklist.Add(usr.Id);
ConfigHandler.SaveConfig();
await ConfigHandler.SaveConfig().ConfigureAwait(false);
await e.Channel.SendMessage($"`Sucessfully blacklisted user {usr.Name}`").ConfigureAwait(false);
}).ConfigureAwait(false);
});
cgb.CreateCommand(Prefix + "uubl")
.Description($"Unblacklists a mentioned user. | {Prefix}uubl [user_mention]")
.Description($"Unblacklists a mentioned user. | `{Prefix}uubl [user_mention]`")
.Parameter("user", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>
@ -707,7 +707,7 @@ namespace NadekoBot.Modules.Permissions
if (NadekoBot.Config.UserBlacklist.Contains(usr.Id))
{
NadekoBot.Config.UserBlacklist.Remove(usr.Id);
ConfigHandler.SaveConfig();
await ConfigHandler.SaveConfig().ConfigureAwait(false);
await e.Channel.SendMessage($"`Sucessfully unblacklisted user {usr.Name}`").ConfigureAwait(false);
}
else
@ -718,7 +718,7 @@ namespace NadekoBot.Modules.Permissions
});
cgb.CreateCommand(Prefix + "cbl")
.Description("Blacklists a mentioned channel (#general for example). | ;cbl #some_channel")
.Description($"Blacklists a mentioned channel (#general for example). | `{Prefix}cbl #some_channel`")
.Parameter("channel", ParameterType.Unparsed)
.Do(async e =>
{
@ -727,13 +727,13 @@ namespace NadekoBot.Modules.Permissions
if (!e.Message.MentionedChannels.Any()) return;
var ch = e.Message.MentionedChannels.First();
NadekoBot.Config.UserBlacklist.Add(ch.Id);
ConfigHandler.SaveConfig();
await ConfigHandler.SaveConfig().ConfigureAwait(false);
await e.Channel.SendMessage($"`Sucessfully blacklisted channel {ch.Name}`").ConfigureAwait(false);
}).ConfigureAwait(false);
});
cgb.CreateCommand(Prefix + "cubl")
.Description("Unblacklists a mentioned channel (#general for example). | ;cubl #some_channel")
.Description($"Unblacklists a mentioned channel (#general for example). | `{Prefix}cubl #some_channel`")
.Parameter("channel", ParameterType.Unparsed)
.Do(async e =>
{
@ -742,13 +742,13 @@ namespace NadekoBot.Modules.Permissions
if (!e.Message.MentionedChannels.Any()) return;
var ch = e.Message.MentionedChannels.First();
NadekoBot.Config.UserBlacklist.Remove(ch.Id);
ConfigHandler.SaveConfig();
await ConfigHandler.SaveConfig().ConfigureAwait(false);
await e.Channel.SendMessage($"`Sucessfully blacklisted channel {ch.Name}`").ConfigureAwait(false);
}).ConfigureAwait(false);
});
cgb.CreateCommand(Prefix + "sbl")
.Description("Blacklists a server by a name or id (#general for example). **BOT OWNER ONLY** | ;sbl [servername/serverid]")
.Description($"Blacklists a server by a name or id (#general for example). **BOT OWNER ONLY** | `{Prefix}sbl [servername/serverid]`")
.Parameter("server", ParameterType.Unparsed)
.AddCheck(SimpleCheckers.OwnerOnly())
.Do(async e =>
@ -767,7 +767,7 @@ namespace NadekoBot.Modules.Permissions
}
var serverId = server.Id;
NadekoBot.Config.ServerBlacklist.Add(serverId);
ConfigHandler.SaveConfig();
await ConfigHandler.SaveConfig().ConfigureAwait(false);
//cleanup trivias and typeracing
Modules.Games.Commands.Trivia.TriviaGame trivia;
TriviaCommands.RunningTrivias.TryRemove(serverId, out trivia);
@ -795,7 +795,7 @@ namespace NadekoBot.Modules.Permissions
throw new ArgumentOutOfRangeException("secs", "Invalid second parameter. (Must be a number between 0 and 3600)");
PermissionsHandler.SetCommandCooldown(e.Server, command, secs);
await PermissionsHandler.SetCommandCooldown(e.Server, command, secs).ConfigureAwait(false);
if(secs == 0)
await e.Channel.SendMessage($"Command **{command}** has no coooldown now.").ConfigureAwait(false);
else

View File

@ -30,8 +30,6 @@ namespace NadekoBot.Modules.Searches.Commands
}
private static Dictionary<string, CachedChampion> CachedChampionImages = new Dictionary<string, CachedChampion>();
private readonly object cacheLock = new object();
private System.Timers.Timer clearTimer { get; } = new System.Timers.Timer();
public LoLCommands(DiscordModule module) : base(module)
@ -42,7 +40,6 @@ namespace NadekoBot.Modules.Searches.Commands
{
try
{
lock (cacheLock)
CachedChampionImages = CachedChampionImages
.Where(kvp => DateTime.Now - kvp.Value.AddedAt > new TimeSpan(1, 0, 0))
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
@ -87,10 +84,8 @@ namespace NadekoBot.Modules.Searches.Commands
var resolvedRole = role;
var name = e.GetArg("champ").Replace(" ", "").ToLower();
CachedChampion champ = null;
lock (cacheLock)
{
CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ);
}
if(CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ))
if (champ != null)
{
champ.ImageStream.Position = 0;
@ -121,13 +116,9 @@ namespace NadekoBot.Modules.Searches.Commands
role = allData[0]["role"].ToString();
resolvedRole = ResolvePos(role);
}
lock (cacheLock)
{
CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ);
}
if(CachedChampionImages.TryGetValue(name + "_" + resolvedRole, out champ))
if (champ != null)
{
Console.WriteLine("Sending lol image from cache.");
champ.ImageStream.Position = 0;
await e.Channel.SendFile("champ.png", champ.ImageStream).ConfigureAwait(false);
return;

View File

@ -68,7 +68,7 @@ namespace NadekoBot.Modules.Searches.Commands
}
}
catch { }
ConfigHandler.SaveConfig();
await ConfigHandler.SaveConfig().ConfigureAwait(false);
};
checkTimer.Start();
}
@ -254,7 +254,7 @@ namespace NadekoBot.Modules.Searches.Commands
}
config.ObservingStreams.Remove(toRemove);
ConfigHandler.SaveConfig();
await ConfigHandler.SaveConfig().ConfigureAwait(false);
await e.Channel.SendMessage($":ok: Removed `{toRemove.Username}`'s stream from notifications.").ConfigureAwait(false);
});

View File

@ -48,7 +48,7 @@ namespace NadekoBot.Modules.Searches
commands.ForEach(cmd => cmd.Init(cgb));
cgb.CreateCommand(Prefix + "we")
.Description($"Shows weather data for a specified city and a country. BOTH ARE REQUIRED. Use country abbrevations. | {Prefix}we Moscow RF")
.Description($"Shows weather data for a specified city and a country. BOTH ARE REQUIRED. Use country abbrevations. | `{Prefix}we Moscow RF`")
.Parameter("city", ParameterType.Required)
.Parameter("country", ParameterType.Required)
.Do(async e =>
@ -69,7 +69,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
cgb.CreateCommand(Prefix + "yt")
.Parameter("query", ParameterType.Unparsed)
.Description("Searches youtubes and shows the first result")
.Description($"Searches youtubes and shows the first result | `{Prefix}yt query`")
.Do(async e =>
{
if (!(await SearchHelper.ValidateQuery(e.Channel, e.GetArg("query")).ConfigureAwait(false))) return;
@ -106,7 +106,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
cgb.CreateCommand(Prefix + "imdb")
.Parameter("query", ParameterType.Unparsed)
.Description("Queries imdb for movies or series, show first result.")
.Description($"Queries imdb for movies or series, show first result. | `{Prefix}imdb query`")
.Do(async e =>
{
if (!(await SearchHelper.ValidateQuery(e.Channel, e.GetArg("query")).ConfigureAwait(false))) return;
@ -130,7 +130,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
cgb.CreateCommand(Prefix + "mang")
.Alias(Prefix + "manga").Alias(Prefix + "mq")
.Parameter("query", ParameterType.Unparsed)
.Description("Queries anilist for a manga and shows the first result.")
.Description($"Queries anilist for a manga and shows the first result. | `{Prefix}mq query`")
.Do(async e =>
{
if (!(await SearchHelper.ValidateQuery(e.Channel, e.GetArg("query")).ConfigureAwait(false))) return;
@ -157,8 +157,16 @@ $@"🌍 **Weather for** 【{obj["target"]}】
.ConfigureAwait(false);
});
cgb.CreateCommand(Prefix + "randomdog")
.Alias(Prefix + "woof")
.Description("Shows a random dog image.")
.Do(async e =>
{
await e.Channel.SendMessage("http://random.dog/" + await SearchHelper.GetResponseStringAsync("http://random.dog/woof").ConfigureAwait(false)).ConfigureAwait(false);
});
cgb.CreateCommand(Prefix + "i")
.Description("Pulls the first image found using a search parameter. Use ~ir for different results. | ~i cute kitten")
.Description($"Pulls the first image found using a search parameter. Use ~ir for different results. | `{Prefix}i cute kitten`")
.Parameter("query", ParameterType.Unparsed)
.Do(async e =>
{
@ -184,7 +192,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
});
cgb.CreateCommand(Prefix + "ir")
.Description("Pulls a random image using a search parameter. | ~ir cute kitten")
.Description($"Pulls a random image using a search parameter. | `{Prefix}ir cute kitten`")
.Parameter("query", ParameterType.Unparsed)
.Do(async e =>
{
@ -211,7 +219,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
});
cgb.CreateCommand(Prefix + "lmgtfy")
.Description("Google something for an idiot.")
.Description($"Google something for an idiot. | `{Prefix}lmgtfy query`")
.Parameter("ffs", ParameterType.Unparsed)
.Do(async e =>
{
@ -222,7 +230,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
cgb.CreateCommand(Prefix + "google")
.Alias(Prefix + "g")
.Description("Get a google search link for some terms.")
.Description($"Get a google search link for some terms. | `{Prefix}google query`")
.Parameter("terms", ParameterType.Unparsed)
.Do(async e =>
{
@ -234,7 +242,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
});
cgb.CreateCommand(Prefix + "hs")
.Description("Searches for a Hearthstone card and shows its image. Takes a while to complete. |~hs Ysera")
.Description($"Searches for a Hearthstone card and shows its image. Takes a while to complete. | `{Prefix}hs Ysera`")
.Parameter("name", ParameterType.Unparsed)
.Do(async e =>
{
@ -275,7 +283,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
});
cgb.CreateCommand(Prefix + "ud")
.Description("Searches Urban Dictionary for a word. |~ud Pineapple")
.Description($"Searches Urban Dictionary for a word. | `{Prefix}ud Pineapple`")
.Parameter("query", ParameterType.Unparsed)
.Do(async e =>
{
@ -304,7 +312,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
});
// thanks to Blaubeerwald
cgb.CreateCommand(Prefix + "#")
.Description("Searches Tagdef.com for a hashtag. |~# ff")
.Description($"Searches Tagdef.com for a hashtag. | `{Prefix}# ff`")
.Parameter("query", ParameterType.Unparsed)
.Do(async e =>
{
@ -389,7 +397,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
});
cgb.CreateCommand(Prefix + "revav")
.Description("Returns a google reverse image search for someone's avatar.")
.Description($"Returns a google reverse image search for someone's avatar. | `{Prefix}revav \"@SomeGuy\"")
.Parameter("user", ParameterType.Unparsed)
.Do(async e =>
{
@ -406,7 +414,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
});
cgb.CreateCommand(Prefix + "revimg")
.Description("Returns a google reverse image search for an image from a link.")
.Description($"Returns a google reverse image search for an image from a link. | `{Prefix}revav Image link`")
.Parameter("image", ParameterType.Unparsed)
.Do(async e =>
{
@ -418,7 +426,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
});
cgb.CreateCommand(Prefix + "safebooru")
.Description("Shows a random image from safebooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~safebooru yuri+kissing")
.Description($"Shows a random image from safebooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `{Prefix}safebooru yuri+kissing`")
.Parameter("tag", ParameterType.Unparsed)
.Do(async e =>
{
@ -431,7 +439,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
});
cgb.CreateCommand(Prefix + "wiki")
.Description("Gives you back a wikipedia link")
.Description($"Gives you back a wikipedia link | `{Prefix}wiki query`")
.Parameter("query", ParameterType.Unparsed)
.Do(async e =>
{
@ -445,7 +453,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
});
cgb.CreateCommand(Prefix + "clr")
.Description("Shows you what color corresponds to that hex. | `~clr 00ff00`")
.Description($"Shows you what color corresponds to that hex. | `{Prefix}clr 00ff00`")
.Parameter("color", ParameterType.Unparsed)
.Do(async e =>
{
@ -470,7 +478,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
cgb.CreateCommand(Prefix + "videocall")
.Description("Creates a private <http://www.appear.in> video call link for you and other mentioned people. The link is sent to mentioned people via a private message.")
.Description($"Creates a private <http://www.appear.in> video call link for you and other mentioned people. The link is sent to mentioned people via a private message. | `{Prefix}videocall \"@SomeGuy\"`")
.Parameter("arg", ParameterType.Unparsed)
.Do(async e =>
{
@ -494,7 +502,7 @@ $@"🌍 **Weather for** 【{obj["target"]}】
cgb.CreateCommand(Prefix + "av")
.Alias(Prefix + "avatar")
.Parameter("mention", ParameterType.Required)
.Description("Shows a mentioned person's avatar. | ~av @X")
.Description($"Shows a mentioned person's avatar. | `{Prefix}av @X`")
.Do(async e =>
{
var usr = e.Channel.FindUsers(e.GetArg("mention")).FirstOrDefault();

View File

@ -14,7 +14,7 @@ namespace NadekoBot.Modules.Translator
{
cgb.CreateCommand(Module.Prefix + "translate")
.Alias(Module.Prefix + "trans")
.Description($"Translates from>to text. From the given language to the destiation language. | {Module.Prefix}trans en>fr Hello")
.Description($"Translates from>to text. From the given language to the destiation language. | `{Module.Prefix}trans en>fr Hello`")
.Parameter("langs", ParameterType.Required)
.Parameter("text", ParameterType.Unparsed)
.Do(TranslateFunc());

View File

@ -71,7 +71,7 @@ namespace NadekoBot.Modules.Trello
cgb.CreateCommand(Prefix + "bind")
.Description("Bind a trello bot to a single channel. " +
"You will receive notifications from your board when something is added or edited." +
" | bind [board_id]")
$" | `{Prefix}bind [board_id]`")
.Parameter("board_id", Discord.Commands.ParameterType.Required)
.Do(async e =>
{
@ -116,7 +116,7 @@ namespace NadekoBot.Modules.Trello
});
cgb.CreateCommand(Prefix + "cards")
.Description("Lists all cards from the supplied list. You can supply either a name or an index.")
.Description($"Lists all cards from the supplied list. You can supply either a name or an index. | `{Prefix}cards index`")
.Parameter("list_name", Discord.Commands.ParameterType.Unparsed)
.Do(async e =>
{

View File

@ -31,7 +31,7 @@ namespace NadekoBot.Modules.Utility
commands.ForEach(cmd => cmd.Init(cgb));
cgb.CreateCommand(Prefix + "whoplays")
.Description("Shows a list of users who are playing the specified game.")
.Description($"Shows a list of users who are playing the specified game. | `{Prefix}whoplays Overwatch`")
.Parameter("game", ParameterType.Unparsed)
.Do(async e =>
{
@ -52,16 +52,15 @@ namespace NadekoBot.Modules.Utility
});
cgb.CreateCommand(Prefix + "inrole")
.Description("Lists every person from the provided role or roles (separated by a ',') on this server.")
.Description($"Lists every person from the provided role or roles (separated by a ',') on this server. If the list is too long for 1 message, you must have Manage Messages permission. | `{Prefix}inrole Role`")
.Parameter("roles", ParameterType.Unparsed)
.Do(async e =>
{
await Task.Run(async () =>
{
if (!e.User.ServerPermissions.MentionEveryone) return;
var arg = e.GetArg("roles").Split(',').Select(r => r.Trim());
string send = $"`Here is a list of users in a specfic role:`";
foreach (var roleStr in arg.Where(str => !string.IsNullOrWhiteSpace(str)))
foreach (var roleStr in arg.Where(str => !string.IsNullOrWhiteSpace(str) && str != "@everyone" && str != "everyone"))
{
var role = e.Server.FindRoles(roleStr).FirstOrDefault();
if (role == null) continue;
@ -71,6 +70,11 @@ namespace NadekoBot.Modules.Utility
while (send.Length > 2000)
{
if (!e.User.ServerPermissions.ManageMessages)
{
await e.Channel.SendMessage($"{e.User.Mention} you are not allowed to use this command on roles with a lot of users in them to prevent abuse.");
return;
}
var curstr = send.Substring(0, 2000);
await
e.Channel.Send(curstr.Substring(0,
@ -110,7 +114,7 @@ namespace NadekoBot.Modules.Utility
});
cgb.CreateCommand(Prefix + "userid").Alias(Prefix + "uid")
.Description("Shows user ID.")
.Description($"Shows user ID. | `{Prefix}uid` or `{Prefix}uid \"@SomeGuy\"")
.Parameter("user", ParameterType.Unparsed)
.Do(async e =>
{
@ -122,11 +126,11 @@ namespace NadekoBot.Modules.Utility
});
cgb.CreateCommand(Prefix + "channelid").Alias(Prefix + "cid")
.Description("Shows current channel ID.")
.Description($"Shows current channel ID. | `{Prefix}cid`")
.Do(async e => await e.Channel.SendMessage("This channel's ID is " + e.Channel.Id).ConfigureAwait(false));
cgb.CreateCommand(Prefix + "serverid").Alias(Prefix + "sid")
.Description("Shows current server ID.")
.Description($"Shows current server ID. | `{Prefix}sid`")
.Do(async e => await e.Channel.SendMessage("This server's ID is " + e.Server.Id).ConfigureAwait(false));
cgb.CreateCommand(Prefix + "roles")
@ -144,6 +148,18 @@ namespace NadekoBot.Modules.Utility
}
await e.Channel.SendMessage("`List of roles:` \n• " + string.Join("\n• ", e.Server.Roles)).ConfigureAwait(false);
});
cgb.CreateCommand(Prefix + "channeltopic")
.Alias(Prefix + "ct")
.Description($"Sends current channel's topic as a message. | `{Prefix}ct`")
.Do(async e =>
{
var topic = e.Channel.Topic;
if (string.IsNullOrWhiteSpace(topic))
return;
await e.Channel.SendMessage(topic).ConfigureAwait(false);
});
});
}
}

View File

@ -197,7 +197,7 @@ namespace NadekoBot
return;
}
#if NADEKO_RELEASE
await Task.Delay(90000).ConfigureAwait(false);
await Task.Delay(100000).ConfigureAwait(false);
#else
await Task.Delay(1000).ConfigureAwait(false);
#endif

View File

@ -46,6 +46,7 @@
<Prefer32Bit>true</Prefer32Bit>
<NoWarn>
</NoWarn>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
@ -55,6 +56,7 @@
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'PRIVATE|AnyCPU'">
<DebugSymbols>true</DebugSymbols>
@ -78,13 +80,14 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>TRACE;DEBUG</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
<Optimize>false</Optimize>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
@ -115,6 +118,7 @@
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>true</Prefer32Bit>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Reference Include="libvideo, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
@ -186,6 +190,7 @@
<Compile Include="Classes\FlowersHandler.cs" />
<Compile Include="Modules\Conversations\Commands\RipCommand.cs" />
<Compile Include="Modules\CustomReactions\CustomReactions.cs" />
<Compile Include="Modules\Gambling\Commands\AnimalRacing.cs" />
<Compile Include="Modules\Music\Classes\PlaylistFullException.cs" />
<Compile Include="Modules\Programming\Commands\HaskellRepl.cs" />
<Compile Include="Modules\Programming\ProgrammingModule.cs" />

View File

@ -4,6 +4,8 @@ using Newtonsoft.Json;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Threading;
using System.Threading.Tasks;
namespace NadekoBot.Classes.JSONModels
{
@ -88,6 +90,17 @@ namespace NadekoBot.Classes.JSONModels
public bool IsRotatingStatus { get; set; } = false;
public int BufferSize { get; set; } = 4.MiB();
public string[] RaceAnimals { get; internal set; } = {
"🐼",
"🐻",
"🐧",
"🐨",
"🐬",
"🐞",
"🦀",
"🦄" };
[JsonIgnore]
public List<Quote> Quotes { get; set; } = new List<Quote>();
[JsonIgnore]
@ -187,13 +200,17 @@ Nadeko Support Server: <https://discord.gg/0ehQwTK2RBjAxzEY>";
public static class ConfigHandler
{
private static readonly object configLock = new object();
public static void SaveConfig()
private static readonly SemaphoreSlim configLock = new SemaphoreSlim(1, 1);
public static async Task SaveConfig()
{
lock (configLock)
await configLock.WaitAsync();
try
{
File.WriteAllText("data/config.json", JsonConvert.SerializeObject(NadekoBot.Config, Formatting.Indented));
}
finally {
configLock.Release();
}
}
public static bool IsBlackListed(MessageEventArgs evArgs) => IsUserBlacklisted(evArgs.User.Id) ||

View File

@ -4,7 +4,16 @@
"ForwardToAllOwners": false,
"IsRotatingStatus": false,
"BufferSize": 4194304,
"Quotes": [],
"RaceAnimals": [
"🐼",
"🐻",
"🐧",
"🐨",
"🐬",
"🐞",
"🦀",
"🦄"
],
"RemindMessageFormat": "❗⏰**I've been told to remind you to '%message%' now by %user%.**⏰❗",
"CustomReactions": {
"\\o\\": [

View File

@ -2,7 +2,7 @@
######You can donate on paypal: `nadekodiscordbot@gmail.com`
#NadekoBot List Of Commands
Version: `NadekoBot v0.9.6048.2992`
Version: `NadekoBot v0.9.6051.26856`
### Help
Command and aliases | Description | Usage
----------------|--------------|-------
@ -57,38 +57,38 @@ Command and aliases | Description | Usage
`.listallincidents`, `.lain` | Sends you a file containing all incidents and flags them as read.
`.delmsgoncmd` | Toggles the automatic deletion of user's successful command message to prevent chat flood. Server Manager Only.
`.restart` | Restarts the bot. Might not work. **Bot Owner Only**
`.setrole`, `.sr` | Sets a role for a given user. | .sr @User Guest
`.removerole`, `.rr` | Removes a role from a given user. | .rr @User Admin
`.setrole`, `.sr` | Sets a role for a given user. | `.sr @User Guest`
`.removerole`, `.rr` | Removes a role from a given user. | `.rr @User Admin`
`.renamerole`, `.renr` | Renames a role. Role you are renaming must be lower than bot's highest role. | `.renr "First role" SecondRole`
`.removeallroles`, `.rar` | Removes all roles from a mentioned user. | .rar @User
`.createrole`, `.cr` | Creates a role with a given name. | `.r Awesome Role`
`.rolecolor`, `.rc` | Set a role's color to the hex or 0-255 rgb color value provided. | `.color Admin 255 200 100` or `.color Admin ffba55`
`.ban`, `.b` | Bans a user by id or name with an optional message. | .b "@some Guy" Your behaviour is toxic.
`.softban`, `.sb` | Bans and then unbans a user by id or name with an optional message. | .sb "@some Guy" Your behaviour is toxic.
`.kick`, `.k` | Kicks a mentioned user.
`.mute` | Mutes mentioned user or users.
`.unmute` | Unmutes mentioned user or users.
`.deafen`, `.deaf` | Deafens mentioned user or users
`.undeafen`, `.undef` | Undeafens mentioned user or users
`.delvoichanl`, `.dvch` | Deletes a voice channel with a given name.
`.creatvoichanl`, `.cvch` | Creates a new voice channel with a given name.
`.deltxtchanl`, `.dtch` | Deletes a text channel with a given name.
`.creatxtchanl`, `.ctch` | Creates a new text channel with a given name.
`.removeallroles`, `.rar` | Removes all roles from a mentioned user. | `.rar @User`
`.createrole`, `.cr` | Creates a role with a given name. | `.cr Awesome Role`
`.rolecolor`, `.rc` | Set a role's color to the hex or 0-255 rgb color value provided. | `.rc Admin 255 200 100` or `.rc Admin ffba55`
`.ban`, `.b` | Bans a user by id or name with an optional message. | `.b "@some Guy" Your behaviour is toxic.`
`.softban`, `.sb` | Bans and then unbans a user by id or name with an optional message. | `.sb "@some Guy" Your behaviour is toxic.`
`.kick`, `.k` | Kicks a mentioned user. | `.k "@some Guy" Your behaviour is toxic.`
`.mute` | Mutes mentioned user or users. | `.mute "@Someguy"` or `.mute "@Someguy" "@Someguy"`
`.unmute` | Unmutes mentioned user or users. | `.unmute "@Someguy"` or `.unmute "@Someguy" "@Someguy"`
`.deafen`, `.deaf` | Deafens mentioned user or users | `.deaf "@Someguy"` or `.deaf "@Someguy" "@Someguy"`
`.undeafen`, `.undef` | Undeafens mentioned user or users | `.undef "@Someguy"` or `.undef "@Someguy" "@Someguy"`
`.delvoichanl`, `.dvch` | Deletes a voice channel with a given name. | `.dvch VoiceChannelName`
`.creatvoichanl`, `.cvch` | Creates a new voice channel with a given name. | `.cvch VoiceChannelName`
`.deltxtchanl`, `.dtch` | Deletes a text channel with a given name. | `.dtch TextChannelName`
`.creatxtchanl`, `.ctch` | Creates a new text channel with a given name. | `.ctch TextChannelName`
`.settopic`, `.st` | Sets a topic on the current channel. | `.st My new topic`
`.setchanlname`, `.schn` | Changed the name of the current channel.
`.setchanlname`, `.schn` | Changed the name of the current channel.| `.schn NewName`
`.heap` | Shows allocated memory - **Bot Owner Only!**
`.prune`, `.clr` | `.prune` removes all nadeko's messages in the last 100 messages.`.prune X` removes last X messages from the channel (up to 100)`.prune @Someone` removes all Someone's messages in the last 100 messages.`.prune @Someone X` removes last X 'Someone's' messages in the channel. | `.prune` or `.prune 5` or `.prune @Someone` or `.prune @Someone X`
`.die` | Shuts the bot down and notifies users about the restart. **Bot Owner Only!**
`.setname`, `.newnm` | Give the bot a new name. **Bot Owner Only!**
`.setname`, `.newnm` | Give the bot a new name. **Bot Owner Only!** | .newnm BotName
`.newavatar`, `.setavatar` | Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot Owner Only!** | `.setavatar https://i.ytimg.com/vi/WDudkR1eTMM/maxresdefault.jpg`
`.setgame` | Sets the bots game. **Bot Owner Only!**
`.setgame` | Sets the bots game. **Bot Owner Only!** | `.setgame Playing with kwoth`
`.send` | Send a message to someone on a different server through the bot. **Bot Owner Only!** | `.send serverid|u:user_id Send this to a user!` or `.send serverid|c:channel_id Send this to a channel!`
`.mentionrole`, `.menro` | Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission.
`.mentionrole`, `.menro` | Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission. | `.menro RoleName`
`.unstuck` | Clears the message queue. **Bot Owner Only!**
`.donators` | List of lovely people who donated to keep this project alive.
`.donadd` | Add a donator to the database.
`.announce` | Sends a message to all servers' general channel bot is connected to.**Bot Owner Only!** | .announce Useless spam
`.savechat` | Saves a number of messages to a text file and sends it to you. **Bot Owner Only** | `.chatsave 150`
`.donadd` | Add a donator to the database. | `.donadd Donate Amount`
`.announce` | Sends a message to all servers' general channel bot is connected to.**Bot Owner Only!** | `.announce Useless spam`
`.savechat` | Saves a number of messages to a text file and sends it to you. **Bot Owner Only** | `.savechat 150`
### Utility
Command and aliases | Description | Usage
@ -98,15 +98,16 @@ Command and aliases | Description | Usage
`.serverinfo`, `.sinfo` | Shows info about the server the bot is on. If no channel is supplied, it defaults to current one. | .sinfo Some Server
`.channelinfo`, `.cinfo` | Shows info about the channel. If no channel is supplied, it defaults to current one. | .cinfo #some-channel
`.userinfo`, `.uinfo` | Shows info about the user. If no user is supplied, it defaults a user running the command. | .uinfo @SomeUser
`.whoplays` | Shows a list of users who are playing the specified game.
`.inrole` | Lists every person from the provided role or roles (separated by a ',') on this server.
`.whoplays` | Shows a list of users who are playing the specified game. | `.whoplays Overwatch`
`.inrole` | Lists every person from the provided role or roles (separated by a ',') on this server. If the list is too long for 1 message, you must have Manage Messages permission. | `.inrole Role`
`.checkmyperms` | Checks your userspecific permissions on this channel.
`.stats` | Shows some basic stats for Nadeko.
`.dysyd` | Shows some basic stats for Nadeko.
`.userid`, `.uid` | Shows user ID.
`.channelid`, `.cid` | Shows current channel ID.
`.serverid`, `.sid` | Shows current server ID.
`.userid`, `.uid` | Shows user ID. | `.uid` or `.uid "@SomeGuy"
`.channelid`, `.cid` | Shows current channel ID. | `.cid`
`.serverid`, `.sid` | Shows current server ID. | `.sid`
`.roles` | List all roles on this server or a single user if specified.
`.channeltopic`, `.ct` | Sends current channel's topic as a message. | `.ct`
### Permissions
Command and aliases | Description | Usage
@ -122,38 +123,38 @@ Command and aliases | Description | Usage
`;rolepermscopy`, `;rpc` | Copies BOT PERMISSIONS (not discord permissions) from one role to another. | `;rpc Some Role ~ Some other role`
`;chnlpermscopy`, `;cpc` | Copies BOT PERMISSIONS (not discord permissions) from one channel to another. | `;cpc Some Channel ~ Some other channel`
`;usrpermscopy`, `;upc` | Copies BOT PERMISSIONS (not discord permissions) from one role to another. | `;upc @SomeUser ~ @SomeOtherUser`
`;verbose`, `;v` | Sets whether to show when a command/module is blocked. | ;verbose true
`;verbose`, `;v` | Sets whether to show when a command/module is blocked. | `;verbose true`
`;srvrperms`, `;sp` | Shows banned permissions for this server.
`;roleperms`, `;rp` | Shows banned permissions for a certain role. No argument means for everyone. | ;rp AwesomeRole
`;chnlperms`, `;cp` | Shows banned permissions for a certain channel. No argument means for this channel. | ;cp #dev
`;userperms`, `;up` | Shows banned permissions for a certain user. No argument means for yourself. | ;up Kwoth
`;srvrmdl`, `;sm` | Sets a module's permission at the server level. | ;sm "module name" enable
`;srvrcmd`, `;sc` | Sets a command's permission at the server level. | ;sc "command name" disable
`;rolemdl`, `;rm` | Sets a module's permission at the role level. | ;rm "module name" enable MyRole
`;rolecmd`, `;rc` | Sets a command's permission at the role level. | ;rc "command name" disable MyRole
`;chnlmdl`, `;cm` | Sets a module's permission at the channel level. | ;cm "module name" enable SomeChannel
`;chnlcmd`, `;cc` | Sets a command's permission at the channel level. | ;cc "command name" enable SomeChannel
`;usrmdl`, `;um` | Sets a module's permission at the user level. | ;um "module name" enable SomeUsername
`;usrcmd`, `;uc` | Sets a command's permission at the user level. | ;uc "command name" enable SomeUsername
`;allsrvrmdls`, `;asm` | Sets permissions for all modules at the server level. | ;asm [enable/disable]
`;allsrvrcmds`, `;asc` | Sets permissions for all commands from a certain module at the server level. | ;asc "module name" [enable/disable]
`;allchnlmdls`, `;acm` | Sets permissions for all modules at the channel level. | ;acm [enable/disable] SomeChannel
`;allchnlcmds`, `;acc` | Sets permissions for all commands from a certain module at the channel level. | ;acc "module name" [enable/disable] SomeChannel
`;allrolemdls`, `;arm` | Sets permissions for all modules at the role level. | ;arm [enable/disable] MyRole
`;allrolecmds`, `;arc` | Sets permissions for all commands from a certain module at the role level. | ;arc "module name" [enable/disable] MyRole
`;ubl` | Blacklists a mentioned user. | ;ubl [user_mention]
`;uubl` | Unblacklists a mentioned user. | ;uubl [user_mention]
`;cbl` | Blacklists a mentioned channel (#general for example). | ;cbl #some_channel
`;cubl` | Unblacklists a mentioned channel (#general for example). | ;cubl #some_channel
`;sbl` | Blacklists a server by a name or id (#general for example). **BOT OWNER ONLY** | ;sbl [servername/serverid]
`;roleperms`, `;rp` | Shows banned permissions for a certain role. No argument means for everyone. | `;rp AwesomeRole`
`;chnlperms`, `;cp` | Shows banned permissions for a certain channel. No argument means for this channel. | `;cp #dev`
`;userperms`, `;up` | Shows banned permissions for a certain user. No argument means for yourself. | `;up Kwoth`
`;srvrmdl`, `;sm` | Sets a module's permission at the server level. | `;sm "module name" enable`
`;srvrcmd`, `;sc` | Sets a command's permission at the server level. | `;sc "command name" disable`
`;rolemdl`, `;rm` | Sets a module's permission at the role level. | `;rm "module name" enable MyRole`
`;rolecmd`, `;rc` | Sets a command's permission at the role level. | `;rc "command name" disable MyRole`
`;chnlmdl`, `;cm` | Sets a module's permission at the channel level. | `;cm "module name" enable SomeChannel`
`;chnlcmd`, `;cc` | Sets a command's permission at the channel level. | `;cc "command name" enable SomeChannel`
`;usrmdl`, `;um` | Sets a module's permission at the user level. | `;um "module name" enable SomeUsername`
`;usrcmd`, `;uc` | Sets a command's permission at the user level. | `;uc "command name" enable SomeUsername`
`;allsrvrmdls`, `;asm` | Sets permissions for all modules at the server level. | `;asm [enable/disable]`
`;allsrvrcmds`, `;asc` | Sets permissions for all commands from a certain module at the server level. | `;asc "module name" [enable/disable]`
`;allchnlmdls`, `;acm` | Sets permissions for all modules at the channel level. | `;acm [enable/disable] SomeChannel`
`;allchnlcmds`, `;acc` | Sets permissions for all commands from a certain module at the channel level. | `;acc "module name" [enable/disable] SomeChannel`
`;allrolemdls`, `;arm` | Sets permissions for all modules at the role level. | `;arm [enable/disable] MyRole`
`;allrolecmds`, `;arc` | Sets permissions for all commands from a certain module at the role level. | `;arc "module name" [enable/disable] MyRole`
`;ubl` | Blacklists a mentioned user. | `;ubl [user_mention]`
`;uubl` | Unblacklists a mentioned user. | `;uubl [user_mention]`
`;cbl` | Blacklists a mentioned channel (#general for example). | `;cbl #some_channel`
`;cubl` | Unblacklists a mentioned channel (#general for example). | `;cubl #some_channel`
`;sbl` | Blacklists a server by a name or id (#general for example). **BOT OWNER ONLY** | `;sbl [servername/serverid]`
`;cmdcooldown`, `;cmdcd` | Sets a cooldown per user for a command. Set 0 to clear. | `;cmdcd "some cmd" 5`
`;allcmdcooldowns`, `;acmdcds` | Shows a list of all commands and their respective cooldowns.
### Conversations
Command and aliases | Description | Usage
----------------|--------------|-------
`..` | Adds a new quote with the specified name (single word) and message (no limit). | .. abc My message
`...` | Shows a random quote with a specified name. | .. abc
`..` | Adds a new quote with the specified name (single word) and message (no limit). | `.. abc My message`
`...` | Shows a random quote with a specified name. | `... abc`
`..qdel`, `..quotedelete` | Deletes all quotes with the specified keyword. You have to either be bot owner or the creator of the quote to delete it. | `..qdel abc`
`@BotName rip` | Shows a grave image of someone with a start year | @NadekoBot rip @Someone 2000
`@BotName die` | Works only for the owner. Shuts the bot down.
@ -173,11 +174,13 @@ Command and aliases | Description | Usage
`$roll` | Rolls 0-100. If you supply a number [x] it rolls up to 30 normal dice. If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | $roll or $roll 7 or $roll 3d5
`$rolluo` | Rolls 0-100. If you supply a number [x] it rolls up to 30 normal dice (unordered). If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | $roll or $roll 7 or $roll 3d5
`$nroll` | Rolls in a given range. | `$nroll 5` (rolls 0-5) or `$nroll 5-15`
`$raffle` | Prints a name and ID of a random user from the online list from the (optional) role.
`$race` | Starts a new animal race.
`$joinrace`, `$jr` | Joins a new race. You can specify an amount of flowers for betting (optional). You will get YourBet*(participants-1) back if you win. | `$jr` or `$jr 5`
`$raffle` | Prints a name and ID of a random user from the online list from the (optional) role. | `$raffle` or `$raffle RoleName
`$$$` | Check how much NadekoFlowers a person has. (Defaults to yourself) | `$$$` or `$$$ @Someone`
`$give` | Give someone a certain amount of NadekoFlowers
`$award` | Gives someone a certain amount of flowers. **Bot Owner Only!** | `$award 100 @person`
`$take` | Takes a certain amount of flowers from someone. **Bot Owner Only!**
`$take` | Takes a certain amount of flowers from someone. **Bot Owner Only!** | `$take 1 "@someguy"`
`$betroll`, `$br` | Bets a certain amount of NadekoFlowers and rolls a dice. Rolling over 66 yields x2 flowers, over 90 - x3 and 100 x10. | $br 5
`$leaderboard`, `$lb` |
@ -196,9 +199,9 @@ Command and aliases | Description | Usage
`>plant` | Spend a flower to plant it in this channel. (If bot is restarted or crashes, flower will be lost)
`>gencurrency`, `>gc` | Toggles currency generation on this channel. Every posted message will have 2% chance to spawn a NadekoFlower. Optional parameter cooldown time in minutes, 5 minutes by default. Requires Manage Messages permission. | `>gc` or `>gc 60`
`>leet` | Converts a text to leetspeak with 6 (1-6) severity levels | >leet 3 Hello
`>choose` | Chooses a thing from a list of things | >choose Get up;Sleep;Sleep more
`>8ball` | Ask the 8ball a yes/no question.
`>rps` | Play a game of rocket paperclip scissors with Nadeko. | >rps scissors
`>choose` | Chooses a thing from a list of things | `>choose Get up;Sleep;Sleep more`
`>8ball` | Ask the 8ball a yes/no question. | `>8ball should i do something`
`>rps` | Play a game of rocket paperclip scissors with Nadeko. | `>rps scissors`
`>linux` | Prints a customizable Linux interjection | `>linux Spyware Windows`
### Music
@ -234,7 +237,7 @@ Command and aliases | Description | Usage
`!!load` | Loads a playlist under a certain name. | `!!load classical-1`
`!!playlists`, `!!pls` | Lists all playlists. Paginated. 20 per page. Default page is 0. | `!!pls 1`
`!!deleteplaylist`, `!!delpls` | Deletes a saved playlist. Only if you made it or if you are the bot owner. | `!!delpls animu-5`
`!!goto` | Goes to a specific time in seconds in a song.
`!!goto` | Goes to a specific time in seconds in a song. | !!goto 30
`!!getlink`, `!!gl` | Shows a link to the currently playing song.
`!!autoplay`, `!!ap` | Toggles autoplay - When the song is finished, automatically queue a related youtube song. (Works only for youtube songs and when queue is empty)
@ -262,41 +265,42 @@ Command and aliases | Description | Usage
`~pokemonability`, `~pokeab` | Searches for a pokemon ability.
`~memelist` | Pulls a list of memes you can use with `~memegen` from http://memegen.link/templates/
`~memegen` | Generates a meme from memelist with top and bottom text. | `~memegen biw "gets iced coffee" "in the winter"`
`~we` | Shows weather data for a specified city and a country. BOTH ARE REQUIRED. Use country abbrevations. | ~we Moscow RF
`~yt` | Searches youtubes and shows the first result
`~we` | Shows weather data for a specified city and a country. BOTH ARE REQUIRED. Use country abbrevations. | `~we Moscow RF`
`~yt` | Searches youtubes and shows the first result | `~yt query`
`~ani`, `~anime`, `~aq` | Queries anilist for an anime and shows the first result.
`~imdb` | Queries imdb for movies or series, show first result.
`~mang`, `~manga`, `~mq` | Queries anilist for a manga and shows the first result.
`~imdb` | Queries imdb for movies or series, show first result. | `~imdb query`
`~mang`, `~manga`, `~mq` | Queries anilist for a manga and shows the first result. | `~mq query`
`~randomcat`, `~meow` | Shows a random cat image.
`~i` | Pulls the first image found using a search parameter. Use ~ir for different results. | ~i cute kitten
`~ir` | Pulls a random image using a search parameter. | ~ir cute kitten
`~lmgtfy` | Google something for an idiot.
`~google`, `~g` | Get a google search link for some terms.
`~hs` | Searches for a Hearthstone card and shows its image. Takes a while to complete. | ~hs Ysera
`~ud` | Searches Urban Dictionary for a word. | ~ud Pineapple
`~#` | Searches Tagdef.com for a hashtag. | ~# ff
`~randomdog`, `~woof` | Shows a random dog image.
`~i` | Pulls the first image found using a search parameter. Use ~ir for different results. | `~i cute kitten`
`~ir` | Pulls a random image using a search parameter. | `~ir cute kitten`
`~lmgtfy` | Google something for an idiot. | `~lmgtfy query`
`~google`, `~g` | Get a google search link for some terms. | `~google query`
`~hs` | Searches for a Hearthstone card and shows its image. Takes a while to complete. | `~hs Ysera`
`~ud` | Searches Urban Dictionary for a word. | `~ud Pineapple`
`~#` | Searches Tagdef.com for a hashtag. | `~# ff`
`~quote` | Shows a random quote.
`~catfact` | Shows a random catfact from <http://catfacts-api.appspot.com/api/facts>
`~yomama`, `~ym` | Shows a random joke from <http://api.yomomma.info/>
`~randjoke`, `~rj` | Shows a random joke from <http://tambal.azurewebsites.net/joke/random>
`~chucknorris`, `~cn` | Shows a random chucknorris joke from <http://tambal.azurewebsites.net/joke/random>
`~magicitem`, `~mi` | Shows a random magicitem from <https://1d4chan.org/wiki/List_of_/tg/%27s_magic_items>
`~revav` | Returns a google reverse image search for someone's avatar.
`~revimg` | Returns a google reverse image search for an image from a link.
`~safebooru` | Shows a random image from safebooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~safebooru yuri+kissing
`~wiki` | Gives you back a wikipedia link
`~revav` | Returns a google reverse image search for someone's avatar. | `~revav "@SomeGuy"
`~revimg` | Returns a google reverse image search for an image from a link. | `~revav Image link`
`~safebooru` | Shows a random image from safebooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `~safebooru yuri+kissing`
`~wiki` | Gives you back a wikipedia link | `~wiki query`
`~clr` | Shows you what color corresponds to that hex. | `~clr 00ff00`
`~videocall` | Creates a private <http://www.appear.in> video call link for you and other mentioned people. The link is sent to mentioned people via a private message.
`~av`, `~avatar` | Shows a mentioned person's avatar. | ~av @X
`~videocall` | Creates a private <http://www.appear.in> video call link for you and other mentioned people. The link is sent to mentioned people via a private message. | `~videocall "@SomeGuy"`
`~av`, `~avatar` | Shows a mentioned person's avatar. | `~av @X`
### NSFW
Command and aliases | Description | Usage
----------------|--------------|-------
`~hentai` | Shows a random NSFW hentai image from gelbooru and danbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~hentai yuri+kissing
`~danbooru` | Shows a random hentai image from danbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~danbooru yuri+kissing
`~gelbooru` | Shows a random hentai image from gelbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~gelbooru yuri+kissing
`~rule34` | Shows a random image from rule34.xx with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | ~rule34 yuri+kissing
`~e621` | Shows a random hentai image from e621.net with a given tag. Tag is optional but preffered. Use spaces for multiple tags. | ~e621 yuri kissing
`~hentai` | Shows a random NSFW hentai image from gelbooru and danbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `~hentai yuri+kissing`
`~danbooru` | Shows a random hentai image from danbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `~danbooru yuri+kissing`
`~gelbooru` | Shows a random hentai image from gelbooru with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `~gelbooru yuri+kissing`
`~rule34` | Shows a random image from rule34.xx with a given tag. Tag is optional but preffered. (multiple tags are appended with +) | `~rule34 yuri+kissing`
`~e621` | Shows a random hentai image from e621.net with a given tag. Tag is optional but preffered. Use spaces for multiple tags. | `~e621 yuri kissing`
`~cp` | We all know where this will lead you to.
`~boobs` | Real adult content.
`~butts`, `~ass`, `~butt` | Real adult content.
@ -305,13 +309,13 @@ Command and aliases | Description | Usage
Command and aliases | Description | Usage
----------------|--------------|-------
`,createwar`, `,cw` | Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name. | ,cw 15 The Enemy Clan
`,startwar`, `,sw` | Starts a war with a given number.
`,startwar`, `,sw` | Starts a war with a given number. | `,sw 1`
`,listwar`, `,lw` | Shows the active war claims by a number. Shows all wars in a short way if no number is specified. | ,lw [war_number] or ,lw
`,claim`, `,call`, `,c` | Claims a certain base from a certain war. You can supply a name in the third optional argument to claim in someone else's place. | ,call [war_number] [base_number] [optional_other_name]
`,claimfinish`, `,cf`, `,cf3`, `,claimfinish3` | Finish your claim with 3 stars if you destroyed a base. Optional second argument finishes for someone else. | ,cf [war_number] [optional_other_name]
`,claimfinish2`, `,cf2` | Finish your claim with 2 stars if you destroyed a base. Optional second argument finishes for someone else. | ,cf [war_number] [optional_other_name]
`,claimfinish1`, `,cf1` | Finish your claim with 1 stars if you destroyed a base. Optional second argument finishes for someone else. | ,cf [war_number] [optional_other_name]
`,unclaim`, `,uncall`, `,uc` | Removes your claim from a certain war. Optional second argument denotes a person in whos place to unclaim | ,uc [war_number] [optional_other_name]
`,unclaim`, `,uncall`, `,uc` | Removes your claim from a certain war. Optional second argument denotes a person in whose place to unclaim | ,uc [war_number] [optional_other_name]
`,endwar`, `,ew` | Ends the war with a given index. | ,ew [war_number]
### Pokegame
@ -326,7 +330,7 @@ Command and aliases | Description | Usage
### Translator
Command and aliases | Description | Usage
----------------|--------------|-------
`~translate`, `~trans` | Translates from>to text. From the given language to the destiation language. | ~trans en>fr Hello
`~translate`, `~trans` | Translates from>to text. From the given language to the destiation language. | `~trans en>fr Hello`
`~translangs` | List the valid languages for translation.
### Customreactions
@ -352,7 +356,7 @@ Command and aliases | Description | Usage
### Trello
Command and aliases | Description | Usage
----------------|--------------|-------
`trello bind` | Bind a trello bot to a single channel. You will receive notifications from your board when something is added or edited. | bind [board_id]
`trello bind` | Bind a trello bot to a single channel. You will receive notifications from your board when something is added or edited. | `trello bind [board_id]`
`trello unbind` | Unbinds a bot from the channel and board.
`trello lists`, `trello list` | Lists all lists yo ;)
`trello cards` | Lists all cards from the supplied list. You can supply either a name or an index.
`trello cards` | Lists all cards from the supplied list. You can supply either a name or an index. | `trello cards index`

@ -1 +1 @@
Subproject commit 3e519b5e0b33175e5a5ca247322b7082de484e15
Subproject commit 3a33731135f1b7dd2efdb51b16158c84bb22da66

1
ffmpeg-installer Submodule

@ -0,0 +1 @@
Subproject commit d593fe3a86be7da9e4177865446f2f5ca58b6be4