protected override async ValueTask AfterExecutedAsync(IResult result, DiscordCommandContext context) { if (result is FailedResult failedResult && !(result is ExecutionFailedResult)) { await ExecutionFailedAsync((EspeonCommandContext)context, failedResult); } }
public override async Task ReplyAsync(DiscordCommandContext ctx, FetchClanResult data) { var embed = new DiscordEmbedBuilder(); var desc = !string.IsNullOrEmpty(data.Clan.Description) ? data.Clan.Description : "-"; embed.WithTitle($"#{data.Clan.Id} {data.Clan.Name}") .WithUrl(data.Clan.URL) .WithColor(Context.DostyaRed) .AddField("Created", data.Clan.CreatedDate?.ToString("u"), true) .AddField("Clan Size", data.Clan.Size.ToString(), true) .AddField("Description", desc, false); var c = 0; foreach (var member in data.Members) { if (++c == 21 && data.Members.Count > 21) { embed.AddField("Other:", $"{data.Members.Count - (c - 1)} more not listed...", true); break; } else { embed.AddField(member.Username, member.JoinDate?.ToShortDateString(), true); } } await ctx.Channel.SendMessageAsync(embed); }
private async Task CommandHandler(SocketMessage msg) { // Do not respond to bot accounts or system messages. if (!(msg is SocketUserMessage message) || msg.Author.IsBot) { return; } // Respond to both mentions and your prefix. #warning Ensure that this configuration variable is set. if (!CommandUtilities.HasPrefix(message.Content, _config["prefix"], out var output)) { return; } var context = new DiscordCommandContext(_client, message, _services); IResult res = await _commands.ExecuteAsync(output, context); switch (res) { case FailedResult fRes: _logger.LogError("Command execution failed with reason: {0}", fRes.Reason); break; } }
public static async Task <bool> CanShowModuleAsync(DiscordCommandContext context, Module module) { if (!(await module.RunChecksAsync(context).ConfigureAwait(false)).IsSuccessful) { return(false); } return(!module.GetType().HasCustomAttribute <HiddenAttribute>()); }
// TODO: Figure out how to do night shifts public override ValueTask <CheckResult> CheckAsync(DiscordCommandContext context) { if (DateTime.UtcNow.Hour > StartHour && DateTime.UtcNow.Hour < EndHour) { return(Success()); } return(Failure($"This command is only usable between {StartHour} Hours and {EndHour} Hours")); }
protected override async ValueTask AfterExecutedAsync(IResult result, DiscordCommandContext ctx0) { var context = (GarlicBreadCommandContext)ctx0; if (!result.IsSuccessful && !(result is CommandNotFoundResult)) { await context.Channel.SendMessageAsync(result.ToString()); } }
public static IMember?GetCurrentMember(this DiscordCommandContext context) { if (context.Author == null || context.GuildId == null) { return(null); } return((IMember)context.Author); }
public static async Task ProcessCommand <TUser>(ChatMessage <TUser> chatMessage, Bot bot) where TUser : User { if (chatMessage.Sender.Id == bot.Id) { return; } string message = chatMessage.Content; string name = message.TrimStart('!').Split(' ')[0].ToLower(); DatabaseObject <CommandModel> commandToExecute = await DatabaseHelper.GetCommandByNameOrAlias(name); if (!commandToExecute.Exists()) { return; } CommandContext context = new CommandContext(DiscordBot.CurrentGuild, TwitchBot.CurrentChannel); if (chatMessage is DiscordChatMessage discordChatMessage) { context = new DiscordCommandContext(context, discordChatMessage.Channel); } if (commandToExecute.Entity.IsStaticCommand) { Command staticCommands = StaticCommands.First((c) => c.Name == name); if (chatMessage.Sender.UserLevel < staticCommands.UserLevel) { return; } staticCommands.DoExecute(chatMessage, bot, context); } else { bot.SendMessage(commandToExecute.Entity.Response, context); } DatabaseObject <CommandMetricsModel> dbMetrics = await DatabaseHelper.GetCommandMetricsByCommand(commandToExecute.Entity); if (dbMetrics.Exists()) { dbMetrics.Entity.ExecutionCount++; await dbMetrics.UpdateInDatabase(SqliteDatabase.Instance); } else { CommandMetricsModel metrics = new CommandMetricsModel(commandToExecute.Entity); await metrics.SaveToDatabase(SqliteDatabase.Instance); } }
public override Task ReplyAsync(DiscordCommandContext ctx, FetchPlayerStatsResult data) { List <string> toJoin; if (data.OldNames.Count > 5) { toJoin = data.OldNames.GetRange(0, 5); toJoin.Add("..."); } else { toJoin = data.OldNames; } var embed = new DiscordEmbedBuilder() .WithColor(Context.DostyaRed) .WithTitle(data.Name) .WithDescription($"**ID: {data.Id}**") .WithColor(DiscordColor.Red); if (toJoin.Count != 0) { embed.AddField("Aliases", string.Join("\n", toJoin)); } if (!(data.LadderStats is null)) { embed.AddField("Ladder:", "```http\n" + $"Rating :: {data.LadderStats?.Rating.ToString("F0") ?? "0"}\n" + $"Ranking :: {data.LadderStats?.Ranking ?? 0}\n" + $"Games :: {data.LadderStats?.GamesPlayed ?? 0}\n" + "```"); } if (!(data.GlobalStats is null)) { embed.AddField("Global:", "```http\n" + $"Rating :: {data.GlobalStats?.Rating.ToString("F0") ?? "0"}\n" + $"Ranking :: {data.GlobalStats?.Ranking ?? 0}\n" + $"Games :: {data.GlobalStats?.GamesPlayed ?? 0}\n" + "```"); } if (!(data.Clan is null)) { embed.AddField($"Clan: {data.Clan?.Name}", "```http\n" + $"Clan Size :: {data.Clan?.Size ?? 0}\n" + $"URL :: {data.Clan?.URL ?? "n/a"}\n" + "```"); } return(ctx.Channel.SendMessageAsync(embed: embed)); }
public Response Execute(DiscordCommandContext commandContext) { if (!DiscordUtils.Main.IsUserBotOwner(commandContext.User)) { return(new TextResponse(Response.Type.Error, "This command can only be used by a bot owner.")); } string playingStatus = string.Join(" ", commandContext.Parameters); DiscordUtils.Main.BotActivity = new Game(playingStatus, ActivityType.Playing); return(new TextResponse(Response.Type.Executed, "Playing status changed.")); }
protected override ValueTask AfterExecutedAsync(IResult result, DiscordCommandContext context) { if (result is CommandOnCooldownResult cooldownResult) { var cooldownTime = cooldownResult.Cooldowns; context.Channel.SendMessageAsync(embed: new LocalEmbedBuilder() .WithTitle($"You are on cooldown!") .WithColor(Color.Red).Build()); } return(base.AfterExecutedAsync(result, context)); }
public static async Task <CustomizableRole> RepairRole(DiscordCommandContext commandContext) { var user = commandContext.User; var guild = commandContext.Guild; DatabaseContext.CustomizableRoles.RemoveRange( DatabaseContext.CustomizableRoles.Where(r => r.UserId == user.Id.RawValue && r.GuildId == guild.Id.RawValue)); await DatabaseContext.SaveChangesAsync(); return(await CreateRole(commandContext)); }
/// <summary> /// Handles simple Http-apis for "reaction" commands /// /// The incoming argument 0 from context is a collection of IMember, but for later purposes /// that type is not required, as we simply use IUser's Mention property, as such converting /// down to the lower interface acceptable to allow for implicit targetting /// </summary> /// <param name="context"></param> public static async Task DoReaction(DiscordCommandContext context) { var client = context.Services.GetRequiredService <HttpClient>(); List <IUser> users = ((IUser?[])context.Arguments[0]).Where(x => x != null).ToList() !; var embed = (new LocalEmbed()) .WithColor(Program.Color); var builder = new LocalMessage(); var apiCommand = Program.ApiCommands[context.Command.Name]; // if no members are specified allow for implicit targeting via the reply system if (users.Count == 0 && context.Message.ReferencedMessage.HasValue && context.Message.ReferencedMessage.Value != null && context.Message.ReferencedMessage.Value.Author != null) { users.Add(context.Message.ReferencedMessage.Value.Author); } // prepare reaction text if needed string?text = null; if (apiCommand.Actions.Ranges.Count > 0) { text = apiCommand.Actions.GetValue(users.Count)?.Random(); } // insert the author as the first "mention" users = users.Prepend(context.Author).ToList(); // insert mentions if (text != null) { // ReSharper disable once CoVariantArrayConversion text = string.Format(text, users.Select(x => x.Mention).ToArray()); embed.WithDescription(text); } var response = await client.GetAsync(apiCommand.Url); if (response.StatusCode != HttpStatusCode.OK) { await new DiscordResponseCommandResult(context, builder.WithEmbed(embed.WithDescription("An error occurred while fetching reaction!"))); return; } // decode the json response, nothing else is supported for the time being // we also only care for one level of the response as of now. var decoded = JsonConvert.DeserializeObject <Dictionary <string, string> >(await response.Content.ReadAsStringAsync()); embed.WithImageUrl(apiCommand.GetFixedImageUrl(decoded[apiCommand.Path])); await new DiscordResponseCommandResult(context, (new LocalMessage()).WithEmbed(embed)); }
public static async Task SetRoleName(DiscordCommandContext commandContext, string name) { var userId = commandContext.Member.Id.RawValue; var guildId = commandContext.Guild.Id.RawValue; var roleDto = DatabaseContext.CustomizableRoles.Where(r => r.GuildId == guildId && r.UserId == userId) .FirstOrDefault() ?? CreateRole(commandContext).Result; if (!commandContext.Guild.Roles.ContainsKey(roleDto.RoleId)) { roleDto = await RepairRole(commandContext); } await commandContext.Guild.Roles[roleDto.RoleId].ModifyAsync(r => r.Name = name); }
protected override async ValueTask OnCommandNotFound(DiscordCommandContext context) { var result = _searchService.GetMostRelevantItem(context.Input.Trim()); if (result is null) { await Client.SendMessageAsync(context.ChannelId, new LocalMessageBuilder().WithContent("No results found").Build()); } else { await Client.SendMessageAsync(context.ChannelId, new LocalMessageBuilder().WithEmbed(result.CreateInfoEmbed()).Build()); } }
public override async Task ReplyAsync(DiscordCommandContext ctx, UnitDatabaseSerachResult data) { var embed = new DiscordEmbedBuilder(); var desc = data.GeneralData.UnitName is not null ? $@"""{data.GeneralData.UnitName}"" {data.Description}" : data.Description; embed.WithAuthor(desc, data.GetUnitDatabaseUrl(), data.GetStrategicIconUrl()) .WithFooter($"{data.GeneralData.FactionName} - {data.Id}") .WithThumbnail(data.GetUnitImageUrl()) .WithTitle("Click here to open unitDB") .WithUrl(data.GetUnitDatabaseUrl()) .WithColor(data.GetFactionColor()); await ctx.Channel.SendMessageAsync(embed : embed); }
internal async ValueTask HandleCommandNotFound(DiscordCommandContext context) { foreach (var service in CommandNotFoundServices) { try { await service.OnCommandNotFound(context).ConfigureAwait(false); } catch (Exception ex) { Logger.LogError(ex, "An exception occurred while executing {0}.{1}().", service.GetType().Name, nameof(DiscordBotService.OnCommandNotFound)); } } }
public static async Task <CustomizableRole> CreateRole(DiscordCommandContext commandContext) { var user = commandContext.User; var guild = commandContext.Guild; var role = await guild.CreateRoleAsync(); DatabaseContext.CustomizableRoles.Add(new CustomizableRole(guild.Id.RawValue, user.Id.RawValue, role.Id.RawValue)); DatabaseContext.SaveChanges(); await commandContext.Guild.GrantRoleAsync(user.Id, role.Id); await role.ModifyAsync(r => r.Name = $"{user.Name}'s Role"); return(new CustomizableRole(guild.Id.RawValue, user.Id.RawValue, role.Id.RawValue)); }
private Task QMmands_MessageCreated(DiscordClient sender, MessageCreateEventArgs e) { if (e.Author.IsBot) { return(Task.CompletedTask); // ignore bots. } _ = Task.Run(async() => { var ctx = new DiscordCommandContext(sender, e, Config.Prefix, _services); await _commands.MessageRecivedAsync(ctx, e.Message.Content); }); return(Task.CompletedTask); }
public Response Execute(DiscordCommandContext commandContext) { if (helpReferenceSite == null || helpReferenceSite.Equals(string.Empty)) { return(new TextResponse(Response.Type.Error, "The bot owner did not include a help reference site URL.")); } else { return(new ExtendedResponse(Response.Type.Executed, new ExtendedResponse.Content.Builder() .AddParagraph("Help Reference Site:", helpReferenceSite) .Build() )); } }
public override async Task ReplyAsync(DiscordCommandContext ctx, TwitchStreamsResult data) { List <string> res = new(); foreach (var s in data.Streams) { res.Add($"{s.UserLogin}: [{s.Title}]({s.StreamLink})"); } var output = new DiscordEmbedBuilder() .WithColor(Context.DostyaRed) .WithTitle("Live Streams") .WithUrl("https://www.twitch.tv/directory/game/Supreme%20Commander%3A%20Forged%20Alliance") .WithDescription(string.Join("\n\n", res).Replace("*", "").Replace("_", "").Replace("`", "")); await ctx.Channel.SendMessageAsync(output); }
public override async Task ReplyAsync(DiscordCommandContext ctx, MapResult data) { var embed = new DiscordEmbedBuilder(); embed.WithTitle("Download map") .WithColor(Context.DostyaRed) .WithUrl(data.DownloadUrl?.AbsoluteUri.Replace(" ", "%20")) .WithAuthor($"{data.Title} (ID #{data.Id})") .WithDescription(data.Description) .AddField("Size", data.Size, true) .AddField("Max Players", data.MaxPlayers.ToString(), true) .AddField("Ranked", data.Ranked.ToString(), true) .AddField("Created At", data.CreatedAt?.ToString("u"), true) .AddField("Author", data.Author) .WithImageUrl(data.PreviewUrl?.AbsoluteUri.Replace(" ", "%20")); await ctx.Channel.SendMessageAsync(embed); }
public Response Execute(DiscordCommandContext commandContext) { return(new TextResponse(Response.Type.Executed, string.Format(INVITE_LINK_FORMAT, commandContext.Self.Id) )); }
public EvalGlobals(DiscordCommandContext context) { Context = context; }
public async Task <LocalEmbedBuilder> CreateCommandEmbedAsync(Command command, DiscordCommandContext context) { var embed = new LocalEmbedBuilder { Title = "Command information", Description = $"{Markdown.Code(command.FullAliases.First())}: {command.Description ?? "No description provided."}", Color = Color.Pink }; if (command.Remarks != null) { embed.Description += " " + command.Remarks; } if (command.FullAliases.Count > 1) { embed.AddField("Aliases", string.Join(", ", command.FullAliases.Skip(1)), true); } if (command.Parameters.Count > 0) { embed.AddField("Parameters", string.Join("\n", command.Parameters.Select(p => FormatParameter(context, p)))); } if (command.CustomArgumentParserType == null) { var cExecString = $"{context.Prefix}{command.FullAliases.First()} {string.Join(" ", command.Parameters.Select(a => $"{(a.IsOptional ? "[" : "{")}{a.Name}{(a.IsOptional ? "]" : "}")}"))}"; embed.AddField("Usage", cExecString); }
protected override async ValueTask AfterExecutedAsync(IResult result, DiscordCommandContext context) { var ctx = (AatroxCommandContext)context; if (result.IsSuccessful) { await ctx.EndAsync(); return; } if (result is CommandNotFoundResult) { string?cmdName; var index = 0; var split = ctx.Message.Content.Substring(ctx.Prefix.ToString() !.Length) .Split(Separator, StringSplitOptions.RemoveEmptyEntries); var maxIndex = split.Length; do { string toLev = (index == 0 ? "" : Separator) + string.Join(Separator, split.Take(maxIndex)); maxIndex--; //toLev += (index == 0 ? "" : Separator) + split[index]; cmdName = toLev.Levenshtein(this); index++; } while (string.IsNullOrWhiteSpace(cmdName) && index < split.Length); if (string.IsNullOrWhiteSpace(cmdName)) { return; } maxIndex++; string?cmdParams = null; while (maxIndex < split.Length) { cmdParams += " " + split[maxIndex++]; } var tryResult = await ExecuteAsync(cmdName + cmdParams, ctx); if (tryResult.IsSuccessful) { return; } result = tryResult; } await ctx.EndAsync(); var str = new StringBuilder(); switch (result) { case ChecksFailedResult err: str.AppendLine("The following check(s) failed:"); foreach (var(check, error) in err.FailedChecks) { str.AppendLine($"[`{(check as AatroxCheckAttribute)?.Name ?? check.GetType().Name}`]: `{error}`"); } break; case TypeParseFailedResult err: str.AppendLine(err.Reason); break; case ArgumentParseFailedResult _: str.AppendLine($"The syntax of the command `{ctx.Command.FullAliases[0]}` was wrong."); break; case OverloadsFailedResult err: str.AppendLine($"I can't find any valid overload for the command `{ctx.Command.Name}`."); foreach (var overload in err.FailedOverloads) { str.AppendLine($"[`{overload.Key.Name}`] -> `{overload.Value.Reason}`"); } break; case ParameterChecksFailedResult err: str.AppendLine("The following parameter check(s) failed:"); foreach (var(check, error) in err.FailedChecks) { str.AppendLine($"[`{check.Parameter.Name}`]: `{error}`"); } break; case ExecutionFailedResult _: //this should be handled in the CommandErrored event or in the Custom Result case. case CommandNotFoundResult _: //this is handled at the beginning of this method with levenshtein thing. break; case CommandOnCooldownResult err: var remainingTime = err.Cooldowns.OrderByDescending(x => x.RetryAfter).FirstOrDefault(); str.AppendLine($"You're being rate limited! Please retry after {remainingTime.RetryAfter.Humanize()}."); break; default: str.AppendLine($"Unknown error: {result}"); break; } if (str.Length == 0) { return; } var embed = new LocalEmbedBuilder { Color = _configuration.DefaultEmbedColor, Title = "Something went wrong!" }; embed.WithFooter($"Type '{ctx.Prefix}help {ctx.Command?.FullAliases[0] ?? ctx.Command?.FullAliases[0] ?? ""}' for more information."); embed.AddField("__Command/Module__", ctx.Command?.Name ?? ctx.Command?.Module?.Name ?? "Unknown command...", true); embed.AddField("__Author__", ctx.User.FullName(), true); embed.AddField("__Error(s)__", str.ToString()); _logger.Warn($"{ctx.User.Id} - {ctx.Guild.Id} ::> Command errored: {ctx.Command?.Name ?? "-unknown command-"}"); await ctx.Channel.SendMessageAsync("", false, embed.Build()); await ctx.DisposeAsync(); }
public YieldDisposable(DiscordCommandContext context) { _context = context; }
public override ValueTask <TypeParserResult <FromUntilParameters> > ParseAsync(Parameter parameter, string value, DiscordCommandContext context) { string[] parameters = value.Split(new[] { " until ", " to " }, StringSplitOptions.RemoveEmptyEntries); if (parameters.Length != 2) { return(Failure("Please provide two valid DateTimes separated by \"until\" or \"to\". (eg. \"2pm until 5:30pm\")")); } string startsValue = parameters[0]; string expiresValue = parameters[1]; if (DateTime.TryParse(startsValue, out DateTime starts) && DateTime.TryParse(expiresValue, out DateTime expires)) { starts = starts.ToUniversalTime(); expires = expires.ToUniversalTime(); if (starts < DateTime.UtcNow || expires < DateTime.UtcNow) { return(Failure("Both DateTimes must be in the future.")); } if (starts < expires) { return(Success(new FromUntilParameters(starts, expires))); } else { return(Failure("The first DateTime must be earlier than the second DateTime.")); } } else { return(Failure("Please provide two valid DateTimes separated by \"until\" or \"to\". (eg. \"2pm until 5:30pm\")")); } }
/// <inheritdoc/> public override ValueTask <TypeParserResult <Color> > ParseAsync(Parameter parameter, string value, DiscordCommandContext context) { // Checks for the following hex formats: // #FFF, #FFFFFF, 0xFFFFFF if (value.Length > 2 && (value[0] == '#' && (value.Length == 4 || value.Length == 7) || value[0] == '0' && (value[1] == 'x' || value[1] == 'X') && value.Length <= 8)) { var valueSpan = value.AsSpan(); if (valueSpan[0] == '#') { valueSpan = valueSpan[1..];
public override ValueTask <CheckResult> CheckAsync(object argument, DiscordCommandContext context) => Uri.IsWellFormedUriString(argument as string, UriKind.Absolute) ? Success() : Failure("The provided argument must be a url.");