public static async Task <T> Load <T>(string filePath, ulong setId = 0, bool logExceptions = true) where T : MemoryBase { if (!File.Exists(filePath)) { return(null); } try { var jObj = JObject.Parse(await File.ReadAllTextAsync(filePath)); if (jObj != null) { T result = (T)Activator.CreateInstance(typeof(T)); result.id = setId; result.Initialize(); result.ReadFromJson(jObj); return(result); } } catch (Exception e) { if (logExceptions) { await MopBot.HandleException(e, "An error has occured when loading memory."); } } return(null); }
public async Task ShowShopCommand(string shopId) { var server = Context.server; var memory = server.GetMemory(); var cmdShopServerData = memory.GetData <CommandShopSystem, CommandShopServerData>(); var currencyServerData = memory.GetData <CurrencySystem, CurrencyServerData>(); var shops = cmdShopServerData.Shops; if (!shops.TryGetValue(shopId, out Shop shop)) { throw new BotError($"No such shop: `{shopId}`."); } var embedBuilder = MopBot.GetEmbedBuilder(server) .WithTitle(shop.displayName) .WithDescription(shop.description) .WithThumbnailUrl(shop.thumbnailUrl) .WithFooter(@"Use ""!shop buy rewards <item number>"" to buy stuff!"); var items = shop.Items; if (items != null) { for (int i = 0; i < items.Length; i++) { ShopItem item = items[i]; await shop.SafeItemAction(i, throwError : false, action : async item => { embedBuilder.AddField($"#{i+1} - {item.name}", $"Costs {string.Join(", ",item.prices.Select(price => currencyServerData.Currencies[price.currency].ToString(price.amount)))}"); }); } } await Context.ReplyAsync(embedBuilder.Build()); }
public async Task ShowXPCommand(SocketGuildUser user = null) { user ??= Context.socketServerUser; var serverMemory = MemorySystem.memory[Context.server]; ulong xp = serverMemory[user].GetData <XPSystem, XPServerUserData>().xp; uint level = XPToLevel(xp); uint rank = (uint)serverMemory.GetSubMemories <ServerUserMemory>().Keys .SelectIgnoreNull(key => { var botUser = MopBot.client.GetUser(key); if (botUser == null) { return(null); } return(new KeyValuePair <ulong, ServerUserMemory>?(new KeyValuePair <ulong, ServerUserMemory>(key, serverMemory[botUser]))); }) .OrderByDescending(pair => pair?.Value.GetData <XPSystem, XPServerUserData>().xp ?? 0) .FirstIndex(pair => pair?.Key == user.Id) + 1; ulong thisLevelXP = LevelToXP(level); ulong nextLevelXP = LevelToXP(level + 1); var builder = MopBot.GetEmbedBuilder(Context) .WithAuthor(user.Username, user.GetAvatarUrl()) .WithDescription($"**XP: **{xp-thisLevelXP}/{nextLevelXP-thisLevelXP} ({xp}/{nextLevelXP} Total)\r\n**Level: **{level}\r\n**Rank: **#{rank}"); await Context.socketTextChannel.SendMessageAsync("", embed : builder.Build()); }
public async Task UpdateSystems(bool allowBreak) { for (int i = 0; i < systems.Count; i++) { var system = systems[i]; try { if (!await system.Update()) { if (allowBreak) { break; } } else if (MopBot.client?.ConnectionState == ConnectionState.Connected) { foreach (var server in MopBot.client.Guilds) { if (system.IsEnabledForServer(server)) { await system.ServerUpdate(server); } } } } catch (Exception e) { await MopBot.HandleException(e); break; } } }
public async Task ShowCurrenciesCommand() { var context = Context; var userId = context.user.Id; var currencyServerData = context.server.GetMemory().GetData <CurrencySystem, CurrencyServerData>(); var currencies = currencyServerData.Currencies; if (currencies.Count == 0) { throw new BotError("There are currently no currencies on this server."); } var builder = MopBot.GetEmbedBuilder(context) .WithAuthor($"{context.user.GetDisplayName()}'s Coins & Points", context.user.GetAvatarUrl()); foreach (var nameId in currencies) { var currency = nameId.value; ulong amount = currency.GetAmount(userId); //currencyUserData[id]; builder.AddField( $"{currency.emote ?? "💰"} - **{amount} {StringUtils.ChangeForm(currency.displayName,amount==1)}**", $"{currency.description ?? "No description"}\r\nId: `{nameId.name}`" ); } await context.ReplyAsync(embed : builder.Build()); }
public async Task AvatarCommand(SocketGuildUser user, [Remainder] string args = null) { var embed = MopBot.GetEmbedBuilder(Context) .WithAuthor($"{user.GetDisplayName()}'s avatar") .WithImageUrl(user.GetAvatarUrl(size: 1024)) .WithFooter($"Requested by {Context.socketServerUser.GetDisplayName()}", Context.user.GetAvatarUrl()) .Build(); await Context.ReplyAsync(embed, false); }
public static SocketUserMessage ToSocketUserMessage(this RestUserMessage restMessage, SocketTextChannel channel) { SocketUserMessage msgNew = MopBot.Construct <SocketUserMessage>(new Type[] { typeof(DiscordSocketClient), typeof(ulong), typeof(ISocketMessageChannel), typeof(SocketUser), typeof(MessageSource) }, new object[] { MopBot.client, restMessage.Id, channel, restMessage.Author, restMessage.Source }); typeof(SocketMessage).GetField("<Content>k__BackingField", anyFlags).SetValue(msgNew, restMessage.Content); typeof(SocketUserMessage).GetField("_embeds", anyFlags).SetValue(msgNew, (ImmutableArray <Embed>)restMessage.Embeds); typeof(SocketUserMessage).GetField("_attachments", anyFlags).SetValue(msgNew, (ImmutableArray <Attachment>)restMessage.Attachments); return(msgNew); }
private async Task ExecuteAction(MessageContext context, ModerationPunishment action, string reason, SocketGuildUser user = null) { user ??= context.socketServerUser ?? throw new ArgumentNullException($"Both {nameof(user)} and {nameof(context)}.{nameof(MessageContext.socketServerUser)} are null."); var embedBuilder = MopBot.GetEmbedBuilder(user.Guild) .WithAuthor(user) .WithDescription($"**Reason:** `{reason}`"); bool RequirePermission(DiscordPermission discordPermission) { if (!context.server.CurrentUser.HasChannelPermission(context.socketServerChannel, DiscordPermission.BanMembers)) { action = ModerationPunishment.Announce; embedBuilder.Title = $"{embedBuilder.Title}\r\n**Attempted to execute action '{action}', but the following permission was missing: `{DiscordPermission.BanMembers}`."; return(false); } return(true); } switch (action) { case ModerationPunishment.Kick: if (RequirePermission(DiscordPermission.KickMembers)) { await user.KickAsync(reason : reason); embedBuilder.Title = "User auto-kicked"; } break; case ModerationPunishment.Ban: if (RequirePermission(DiscordPermission.KickMembers)) { await user.BanAsync(reason : reason); embedBuilder.Title = "User auto-banned"; } break; } if (action == ModerationPunishment.Announce) { embedBuilder.Title = "User violation detected"; } var data = context.server.GetMemory().GetData <AutoModerationSystem, AutoModerationServerData>(); await context.socketTextChannel.SendMessageAsync(data.announcementPrefix, embed : embedBuilder.Build()); }
public override async Task OnMessageReceived(MessageContext context) { var server = context.server; var channel = context.socketTextChannel; if (channel == null) { return; } var triviaServerMemory = server.GetMemory().GetData <TriviaSystem, TriviaServerData>(); var qa = triviaServerMemory.currentQuestion; if (qa == null || channel.Id != triviaServerMemory.currentChannel) { return; } var regex = GetCurrentQuestionRegex(triviaServerMemory); string text = context.content.ToLower().RemoveWhitespaces(); var match = regex.Match(context.content); if (match.Success) { triviaServerMemory.currentQuestion = null; var user = context.socketServerUser; CurrencyAmount.TryGiveToUser(ref triviaServerMemory.currencyRewards, user, out string givenString); var timeSpan = DateTime.Now - triviaServerMemory.lastTriviaPost.AddSeconds(triviaServerMemory.postIntervalInSeconds); var embed = MopBot.GetEmbedBuilder(server) .WithDescription($"{user.Mention} wins{(givenString!=null ? $", and gets {givenString}" : null)}!\r\nThe question was `{qa.question}`, and their answer was `{match.Groups[1].Value}`.\r\n\r\nThe next question will come up in `{timeSpan:m'm 's's'}` from now.") .Build(); await channel.SendMessageAsync(embed : embed); var currentUser = server.CurrentUser; if (triviaServerMemory.lockTriviaChannel && currentUser.HasChannelPermission(channel, DiscordPermission.ManageChannel)) { //Lock the channel, since the question has been answered. await channel.ModifyPermissions(currentUser, op => op.Modify(sendMessages: PermValue.Allow)); //Make sure we're still allowed to post await channel.ModifyPermissions(server.EveryoneRole, op => op.Modify(sendMessages: PermValue.Deny)); //Forbid posting for everyone else } return; } }
public async Task ListSystems() { var server = Context.server; var isMaster = Context.user.IsBotMaster(); var builder = MopBot.GetEmbedBuilder(server); foreach (var system in allSystems.Where(s => (!s.Configuration.Hidden || isMaster) && !s.Configuration.AlwaysEnabled).OrderBy(s => s.GetType().Name)) { builder.AddField($"{(system.IsEnabledForServer(server) ? ":white_check_mark:" : ":x:")} - {system.Name}", system.Configuration.Description ?? "`Configuration missing.`"); } await ReplyAsync(embed : builder.Build()); }
public async Task ShowIssue(uint issueId) { var data = Context.server.GetMemory().GetData <IssueSystem, IssueServerData>(); var issue = data.issues.FirstOrDefault(i => i.issueId == issueId) ?? throw new BotError($"An issue with Id #{issueId} could not be found."); var user = Context.user; var builder = MopBot.GetEmbedBuilder(Context) .WithAuthor($"Requested by {user.GetDisplayName()}", user.GetAvatarUrl()) .WithTitle($"Issue #{issue.issueId}") .WithDescription($"**Status:** {StatusText[issue.status]}```\r\n{issue.text}```"); await Context.messageChannel.SendMessageAsync(embed : builder.Build()); }
private static async Task ModifyXP(Func <ulong, ulong> xpModifier, SocketGuildUser user, SocketUserMessage message = null) { var server = user.Guild; var serverMemory = MemorySystem.memory[server]; var userMemory = serverMemory[user]; var xpUserData = userMemory.GetData <XPSystem, XPServerUserData>(); uint prevLvl = XPToLevel(xpUserData.xp); xpUserData.xp = xpModifier(xpUserData.xp); uint newLvl = XPToLevel(xpUserData.xp); if (message != null) { if (newLvl > prevLvl) { try { await message.AddReactionAsync(EmoteUtils.Parse("🌟")); } catch (Exception e) { await MopBot.HandleException(e); } } /*var mentionChannel = (ITextChannel)(serverMemory.GetData<ChannelSystem,ChannelServerData>().GetChannelByRole(ChannelRole.BotArea) ?? channel); * string text = $"{user.Name()} has just reached level {newLvl}! :star:"; * * var xpServerData = serverMemory.GetData<XPSystem,XPServerData>(); * * if(xpServerData.levelRewards.TryGetValue(newLvl,out ulong[] roleIds)) { * var oldAccessLevel = user.GetAccessLevel(); * var oldCommandList = CommandService.commands.Where(h => oldAccessLevel>=h.minAccessLevel); * var roles = roleIds.Select(id => server.GetRole(id)); * * text += $"\r\nThe following roles are now available to them:```{string.Join("\r\n",roles.Select(role => role.Name))}```"; * * await user.AddRolesAsync(roles); * * var newAccessLevel = user.GetAccessLevel(roleIds); * var newCommandList = CommandService.commands.Where(h => newAccessLevel>=h.minAccessLevel); * var newCommandsOnly = newCommandList.Where(h => !oldCommandList.Contains(h)).ToArray(); * * if(newCommandsOnly.Length>0) { * text += $"\r\nThe following commands are now available to them:```{string.Join("\r\n",newCommandsOnly.Select(h => $"{string.Join("/",h.aliases)}-{h.description}"))}```"; * } * } * * await mentionChannel.SendMessageAsync(text);*/ } }
public async Task HelpCommand() { var context = Context; var builder = MopBot.GetEmbedBuilder(context) .WithAuthor($"Commands available to @{context.socketServerUser.GetDisplayName()}:", context.user.GetAvatarUrl()) .WithFooter($"You can type {context.server.GetMemory().GetData<CommandSystem, CommandServerData>().commandPrefix}help <command> to see groups' commands and commands' syntaxes."); foreach ((var aliases, string description, _) in GetAvailableCommands(context.server, context.socketServerUser, true)) { builder.AddField(string.Join("/", aliases), description); } await context.socketTextChannel.SendMessageAsync(embed : builder.Build()); }
public async Task ShowEntry(uint entryId) { var context = Context; var data = context.server.GetMemory().GetData <ChangelogSystem, ChangelogServerData>(); var entry = data.entries.FirstOrDefault(i => i.entryId == entryId); if (entry == null) { throw new BotError($"An entry with Id #{entryId} could not be found."); } var user = context.user; var builder = MopBot.GetEmbedBuilder(context) .WithAuthor($"Requested by {user.GetDisplayName()}", user.GetAvatarUrl()) .WithTitle($"Entry #{entry.entryId}") .WithDescription($"**Status:** {(data.entryTypes.TryGetValue(entry.type, out var entryType) ? $"{entryType.discordPrefix} - {entryType.name}" : $"UNKNOWN (`{entry.type}`)")}```\r\n{entry.text}```");
public EmbedBuilder ToBuilder(SocketGuild server) { var builder = MopBot.GetEmbedBuilder(server); if (authorName != null) { builder.WithAuthor(authorName, imageUrl); } if (description != null) { builder.WithDescription(description); } return(builder); }
public override async Task ServerUpdate(SocketGuild server) { var memory = server.GetMemory().GetData <ConfigurationSystem, ConfigurationServerData>(); string nickname = memory.forcedNickname; var currentUser = server.GetUser(MopBot.client.CurrentUser.Id); if (currentUser != null && !string.Equals(currentUser.Nickname, nickname, StringComparison.InvariantCulture) && !(nickname == "MopBot" && currentUser.Nickname == null) && currentUser.HasDiscordPermission(p => p.ChangeNickname)) { try { await currentUser.ModifyAsync(u => u.Nickname = nickname); } catch (Exception e) { await MopBot.HandleException(e); } } }
public async Task MoveMessagesCommand(SocketTextChannel sourceChannel, int numMessages, SocketTextChannel destinationChannel, ulong bottomMessageId = 0, bool allowGrouping = true) { var context = Context; context.server.CurrentUser.RequirePermission(destinationChannel, DiscordPermission.ManageMessages); var messageList = await CopyMessagesInternal(sourceChannel, numMessages, destinationChannel, bottomMessageId, allowGrouping); try { await context.socketTextChannel.DeleteMessagesAsync(messageList); } catch (Exception e) { await MopBot.HandleException(e); await context.ReplyAsync($"Error deleting messages: ```{string.Join("\r\n", messageList.Select(m => m == null ? "NULL" : m.Id.ToString()))}```"); } }
public async Task SetupShopCommand(string shopId, string displayName, string description = null, string thumbnailUrl = null) { StringUtils.CheckAndLowerStringId(ref shopId); MopBot.CheckForNullOrEmpty(displayName, nameof(displayName)); var context = Context; var cmdShopServerData = context.server.GetMemory().GetData <CommandShopSystem, CommandShopServerData>(); var shops = cmdShopServerData.Shops; if (!shops.TryGetValue(shopId, out Shop shop)) { shops[shopId] = shop = new Shop(); } shop.displayName = displayName; shop.description = description; shop.thumbnailUrl = thumbnailUrl; }
public override async Task Initialize() { if (string.IsNullOrWhiteSpace(GlobalConfiguration.config.token)) { throw new ArgumentException($"Add bot's token to '{GlobalConfiguration.ConfigurationFile}' file."); } MopBot.client = client = new DiscordSocketClient(new DiscordSocketConfig() { LogLevel = LogSeverity.Debug, MessageCacheSize = 1000 }); MopBot.OnClientInit(client); await MopBot.TryCatchLogged("Attempting Login...", () => client.LoginAsync(TokenType.Bot, GlobalConfiguration.config.token.Trim())); await MopBot.TryCatchLogged("Attempting Connection...", () => client.StartAsync()); }
public async Task AddItemCommand(string shopId, string itemName, string itemPrice, string itemCommand) { MopBot.CheckForNullOrEmpty(itemName, nameof(itemName)); MopBot.CheckForNullOrEmpty(itemCommand, nameof(itemCommand)); var serverMemory = Context.server.GetMemory(); var cmdShopServerData = serverMemory.GetData <CommandShopSystem, CommandShopServerData>(); var shops = cmdShopServerData.Shops; if (!shops.TryGetValue(shopId, out Shop shop)) { throw new BotError($"No such shop: `{shopId}`."); } var item = new ShopItem(itemName, CurrencyAmount.ParseMultiple(itemPrice, serverMemory), new SudoCommand(itemCommand, Context.user.Id)); lock (shop) { shop.Items = shop.Items?.Append(item)?.ToArray() ?? new[] { item }; } }
public async Task HelpCommand([Remainder] string cmdOrGroup) { var context = Context; cmdOrGroup = cmdOrGroup.Trim().ToLower(); var match = GroupCommandRegex.Match(cmdOrGroup); if (!match.Success) { throw new BotError($"Invalid input: `{cmdOrGroup}`."); } string groupA = match.Groups[1].Value; string groupB = match.Groups[2].Value; var strComparer = MopBot.StrComparerIgnoreCase; var cmdPrefix = context.server.GetMemory().GetData <CommandSystem, CommandServerData>().commandPrefix; EmbedBuilder builder = null; EmbedBuilder PrepareBuilder() => builder = MopBot.GetEmbedBuilder(context);
public async Task MoveMessagesCommand(int numMessages, SocketGuildChannel channel, ulong bottomMessageId = 0) { var context = Context; context.server.CurrentUser.RequirePermission(channel, DiscordPermission.ManageMessages); if (!(channel is ITextChannel toChannel)) { throw new BotError($"<#{channel.Id}> isn't a text channel."); } var messageList = await CopyMessagesInternal(numMessages, toChannel, bottomMessageId); try { await context.socketTextChannel.DeleteMessagesAsync(messageList); } catch (Exception e) { await MopBot.HandleException(e); await context.ReplyAsync($"Error deleting messages: ```{string.Join("\r\n",messageList.Select(m => m==null ? "NULL" : m.Id.ToString()))}```"); } }
public override async Task OnUserJoined(SocketGuildUser user) { var server = user.Guild; var memory = server.GetMemory(); var welcomeData = memory.GetData <WelcomeSystem, WelcomeServerData>(); if (!server.TryGetTextChannel(welcomeData.channel, out var welcomeChannel)) { return; } string msg; if (!memory.GetSubMemories <ServerUserMemory>().Any(p => p.Key == user.Id)) { msg = welcomeData.messageJoin; } else { msg = welcomeData.messageRejoin; } await welcomeChannel.SendMessageAsync(user.Mention, embed : MopBot.GetEmbedBuilder(server).WithDescription(msg).Build()); }
public override async Task OnMessageReceived(MessageContext message) { var localServerData = message.server.GetMemory().GetData <ChannelLinkingSystem, ChannelLinkingServerData>(); var channelLinks = localServerData.channelLinks; if (channelLinks == null) { return; } ulong channelId = message.messageChannel.Id; if (!channelLinks.TryGetValue(channelId, out ulong linkId)) { return; } var channelLinkingData = MemorySystem.memory.GetData <ChannelLinkingSystem, ChannelLinkingGlobalData>(); if (!channelLinkingData.links.TryGetValue(linkId, out var channelLink)) { channelLinks.Remove(channelId); return; } //string inviteUrl = await BotUtils.GetInviteUrl(message.server); //string linkedServerName = inviteUrl!=null ? $"({message.server.Name})[{inviteUrl}]" : message.server.Name; string authorStr = $"{message.user.Username}#{message.user.Discriminator} [{message.server.Name}/#{message.Channel.Name}]"; string authorAvatarUrl = message.user.GetAvatarUrl(); var builder = MopBot.GetEmbedBuilder(message) .WithColor(message.socketServerUser.Roles.OrderByDescending(r => r.Position).FirstOrDefault(r => !r.Color.ColorEquals(Discord.Color.Default))?.Color ?? Discord.Color.Default) .WithAuthor(authorStr, authorAvatarUrl) //,$@"https://discordapp.com/channels/@me/{message.user.Id}" .WithDescription(message.content);
private static EmbedBuilder GetUserEmbed(SocketGuild server, IUser user) => MopBot.GetEmbedBuilder(server) .WithAuthor(user) .WithFooter($"User ID: {user.Id}") .WithCurrentTimestamp();
public async Task SetQuestionsCommand(string url = null) { var server = Context.server; if (!Context.socketMessage.Attachments.TryGetFirst(a => a.Filename.EndsWith(".txt") || a.Filename.EndsWith(".json"), out Attachment file) && url == null) { await Context.ReplyAsync("Expected a .json file attachment or a link to it."); return; } string filePath = MopBot.GetTempFileName("TriviaQuestions", ".json"); string urlString = file?.Url ?? url; if (!Uri.TryCreate(urlString, UriKind.Absolute, out Uri uri)) { await Context.ReplyAsync($"Invalid Url: `{urlString}`."); return; } using (var client = new WebClient()) { try { client.DownloadFile(uri, filePath); } catch (Exception e) { if (File.Exists(filePath)) { File.Delete(filePath); } throw new BotError($"`{e.GetType().Name}` exception has occured during file download."); } } var json = File.ReadAllText(filePath); File.Delete(filePath); Dictionary <string, string[]> dict; try { dict = JsonConvert.DeserializeObject <Dictionary <string, string[]> >(json); } catch (Exception e) { throw new BotError($"Failed to parse the JSON file: `{e.Message}`."); } if (dict == null) { throw new BotError("Failed to parse the JSON file: Unknown error."); } var triviaServerData = server.GetMemory().GetData <TriviaSystem, TriviaServerData>(); var questions = triviaServerData.questions ??= new List <TriviaQuestion>(); foreach (var pair in dict) { var key = pair.Key; if (string.IsNullOrWhiteSpace(key)) { throw new BotError("Failed to parse the JSON file: Some question is null."); } var value = pair.Value; if (value == null || value.Length == 0) { throw new BotError($"Failed to parse the JSON file: Question `{key}`'s answers are missing or are null."); } questions.Add(new TriviaQuestion(key, value)); } }
public override async Task ServerUpdate(SocketGuild server) { var triviaServerData = server.GetMemory().GetData <TriviaSystem, TriviaServerData>(); if (!triviaServerData.IsReady) { return; //TODO: Let the admins know that this is misconfigured. } var now = DateTime.Now; if ((now - triviaServerData.lastTriviaPost).TotalSeconds <= triviaServerData.postIntervalInSeconds) { return; } triviaServerData.lastTriviaPost = now; triviaServerData.currentChannel = triviaServerData.triviaChannels[MopBot.Random.Next(triviaServerData.triviaChannels.Count)]; var channel = server.GetTextChannel(triviaServerData.currentChannel); if (channel == null) { return; //TODO: Same as above } TriviaQuestion[] validQuestions; //Find questions we didn't pick yet, handle running out of them. while (true) { lock (triviaServerData.questions) { validQuestions = triviaServerData.questions.Where(q => !q.wasPosted).ToArray(); } if (validQuestions.Length == 0) { if (triviaServerData.autoClearCache && triviaServerData.questions.Count > 0) { ClearCache(triviaServerData); continue; } else { await channel.SendMessageAsync($"{server.Owner.Mention} We're out of trivia questions!\r\n\r\nAdd new questions, or..\r\n• Use `!trivia clearcache` to clear list of used questions;\r\n• Use `!trivia autoclearcache true` to automate this process, if you're fully okay with same questions being repeat;"); return; } } break; } //Set new question triviaServerData.currentQuestion = validQuestions[MopBot.Random.Next(validQuestions.Length)]; triviaServerData.currentQuestion.wasPosted = true; currentQuestionRegex = null; //This will cause a new one to be made, when needed. string mention = null; SocketRole role = null; bool disallowRoleMention = false; var currentUser = server.CurrentUser; if (triviaServerData.triviaRole > 0) { role = server.GetRole(triviaServerData.triviaRole); if (role != null) { if (!role.IsMentionable && currentUser.HasDiscordPermission(gp => gp.ManageRoles)) { await role.ModifyAsync(rp => rp.Mentionable = true); disallowRoleMention = true; } mention = role.Mention; } else { triviaServerData.triviaRole = 0; } } var embedBuilder = MopBot.GetEmbedBuilder(server) .WithAuthor("The next question is...") //.WithTitle("The next question is...") .WithDescription($"**{triviaServerData.currentQuestion.question}**") .WithFooter("Type your answer right in this channel!"); if (triviaServerData.thumbnailUrls?.Length > 0 == true) { try { embedBuilder.WithThumbnailUrl(triviaServerData.thumbnailUrls[MopBot.Random.Next(triviaServerData.thumbnailUrls.Length)]); } catch {} } await channel.SendMessageAsync(mention, embed : embedBuilder.Build()); if (disallowRoleMention) { await role.ModifyAsync(rp => rp.Mentionable = false); } if (triviaServerData.lockTriviaChannel && currentUser.HasChannelPermission(channel, DiscordPermission.ManageChannel)) { //Unlock the channel, since there's a question now. await channel.ModifyPermissions(server.EveryoneRole, op => op.SendMessages == PermValue.Deny?op.Modify(sendMessages : PermValue.Inherit) : op); } }