Skip to content

Commit 1db01ef

Browse files
committed
initial slash command tooling
1 parent efa3d60 commit 1db01ef

File tree

3 files changed

+69
-14
lines changed

3 files changed

+69
-14
lines changed

CommandHandlers/UserCommands.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ public static IUserMessage SendReply(IUserMessage message, Embed embed, IMessage
4242
}
4343
}
4444

45+
/// <summary>Sends a reply to a slash command.</summary>
46+
/// <param name="command">The command to reply to.</param>
47+
/// <param name="embed">The embed message to send.</param>
48+
public static void SendReply(SocketSlashCommand command, Embed embed)
49+
{
50+
command.RespondAsync(embed: embed, allowedMentions: AllowedMentions.None).Wait();
51+
}
52+
4553
/// <summary>
4654
/// Sends a "did you mean ...?" style reply. This adds a clickable reaction that triggers an automatic command when clicked by the user that originally did the command within a certain time limit.
4755
/// </summary>
@@ -60,18 +68,36 @@ public static IUserMessage SendDidYouMeanReply(IUserMessage message, string titl
6068
return sentMessage;
6169
}
6270

71+
/// <summary>Sends a generic positive reply to a slash command.</summary>
72+
public static void SendGenericPositiveMessageReply(SocketSlashCommand command, string title, string description)
73+
{
74+
SendReply(command, GetGenericPositiveMessageEmbed(title, description));
75+
}
76+
6377
/// <summary>Sends a generic positive reply to a message in the same channel.</summary>
6478
public static IUserMessage SendGenericPositiveMessageReply(IUserMessage message, string title, string description, IMessageChannel channelBackup = null)
6579
{
6680
return SendReply(message, GetGenericPositiveMessageEmbed(title, description), channelBackup);
6781
}
6882

83+
/// <summary>Sends a generic negative reply to a slash command.</summary>
84+
public static void SendGenericNegativeMessageReply(SocketSlashCommand command, string title, string description)
85+
{
86+
SendReply(command, GetGenericNegativeMessageEmbed(title, description));
87+
}
88+
6989
/// <summary>Sends a generic negative reply to a message in the same channel.</summary>
7090
public static IUserMessage SendGenericNegativeMessageReply(IUserMessage message, string title, string description, IMessageChannel channelBackup = null)
7191
{
7292
return SendReply(message, GetGenericNegativeMessageEmbed(title, description), channelBackup);
7393
}
7494

95+
/// <summary>Sends an error message reply to a slash command in the same channel.</summary>
96+
public static void SendErrorMessageReply(SocketSlashCommand command, string title, string description)
97+
{
98+
SendReply(command, GetErrorMessageEmbed(title, description));
99+
}
100+
75101
/// <summary>Sends an error message reply to a message in the same channel.</summary>
76102
public static IUserMessage SendErrorMessageReply(IUserMessage message, string title, string description, IMessageChannel channelBackup = null)
77103
{

DiscordBot.cs

Lines changed: 40 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using DiscordBotBase.CommandHandlers;
1212
using DiscordBotBase.Reactables;
1313
using FreneticUtilities.FreneticToolkit;
14+
using FreneticUtilities.FreneticExtensions;
1415

1516
namespace DiscordBotBase
1617
{
@@ -41,6 +42,21 @@ public class DiscordBot
4142
/// <summary>A cache of messages sent previously on Discord.</summary>
4243
public DiscordMessageCache Cache;
4344

45+
/// <summary>Lock object for config file saving/loading.</summary>
46+
public static LockObject ConfigSaveLock = new();
47+
48+
/// <summary>Signaled when the bot is stopped.</summary>
49+
public ManualResetEvent StoppedEvent = new(false);
50+
51+
/// <summary>Monitor object to help restart the bot as needed.</summary>
52+
public ConnectionMonitor BotMonitor;
53+
54+
/// <summary>All valid user chat commands in a map of typable command name -> command method.</summary>
55+
public readonly Dictionary<string, Action<CommandData>> ChatCommands = new(1024);
56+
57+
/// <summary>All valid slash commands in a map of typable command name -> command method.</summary>
58+
public readonly Dictionary<string, Action<SocketSlashCommand>> SlashCommands = new(1024);
59+
4460
/// <summary>Bot command response handler.</summary>
4561
/// <param name="message">The message received.</param>
4662
/// <param name="outputUnknowns">Whether to output "unknown command" messages.</param>
@@ -84,7 +100,7 @@ public void Respond(IUserMessage message, bool outputUnknowns, bool wasMentioned
84100
}
85101
string fullMessageCleaned = resultBuilder.ToString();
86102
Console.WriteLine("Found input from: (" + message.Author.Username + "), in channel: " + message.Channel.Name + ": " + fullMessageCleaned);
87-
string commandNameLowered = argsCleaned[0].ToLowerInvariant();
103+
string commandNameLowered = argsCleaned[0].ToLowerFast();
88104
argsCleaned.RemoveAt(0);
89105
argsRaw.RemoveAt(0);
90106
CommandData commandData = new() { Message = message, CleanedArguments = argsCleaned.ToArray(), RawArguments = argsRaw.ToArray(), WasBotMention = wasMentioned };
@@ -107,9 +123,6 @@ public void Respond(IUserMessage message, bool outputUnknowns, bool wasMentioned
107123
}
108124
}
109125

110-
/// <summary>All valid user commands in a map of typable command name -> command method.</summary>
111-
public readonly Dictionary<string, Action<CommandData>> ChatCommands = new(1024);
112-
113126
/// <summary>Saves the config file.</summary>
114127
public void SaveConfig()
115128
{
@@ -119,15 +132,21 @@ public void SaveConfig()
119132
}
120133
}
121134

122-
/// <summary>Lock object for config file saving/loading.</summary>
123-
public static LockObject ConfigSaveLock = new();
124-
125135
/// <summary>Registers a command to a name and any number of aliases.</summary>
126136
public void RegisterCommand(Action<CommandData> command, params string[] names)
127137
{
128138
foreach (string name in names)
129139
{
130-
ChatCommands.Add(name, command);
140+
ChatCommands.Add(name.ToLowerFast(), command);
141+
}
142+
}
143+
144+
/// <summary>Registers a slash command to a name and any number of aliases.</summary>
145+
public void RegisterSlashCommand(Action<SocketSlashCommand> command, params string[] names)
146+
{
147+
foreach (string name in names)
148+
{
149+
SlashCommands.Add(name.ToLowerFast(), command);
131150
}
132151
}
133152

@@ -140,12 +159,6 @@ public void Shutdown()
140159
StoppedEvent.Set();
141160
}
142161

143-
/// <summary>Signaled when the bot is stopped.</summary>
144-
public ManualResetEvent StoppedEvent = new(false);
145-
146-
/// <summary>Monitor object to help restart the bot as needed.</summary>
147-
public ConnectionMonitor BotMonitor;
148-
149162
/// <summary>Initializes the bot object, connects, and runs the active loop.</summary>
150163
public void InitAndRun(string[] args)
151164
{
@@ -304,6 +317,19 @@ public void InitAndRun(string[] args)
304317
Cache.CacheMessage(socketMessage);
305318
return Task.CompletedTask;
306319
};
320+
Client.SlashCommandExecuted += (command) =>
321+
{
322+
if (!ClientConfig.AllowSlashCommandsInDM && command.Channel is not IGuildChannel)
323+
{
324+
command.RespondAsync("Commands don't work there.", ephemeral: true);
325+
return Task.CompletedTask;
326+
}
327+
if (!SlashCommands.TryGetValue(command.CommandName.ToLowerFast(), out Action<SocketSlashCommand> cmd))
328+
{
329+
command.RespondAsync("Unknown command.", ephemeral: true);
330+
}
331+
return Task.CompletedTask;
332+
};
307333
Console.WriteLine("Logging in to Discord...");
308334
Client.LoginAsync(TokenType.Bot, TOKEN).Wait();
309335
Console.WriteLine("Connecting to Discord...");

DiscordBotConfig.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,5 +45,8 @@ public class DiscordBotConfig
4545

4646
/// <summary>What gateway intents to connect with. Defaults to 'AllUnprivileged | GuildMessages | GuildMessageReactions'.</summary>
4747
public GatewayIntents GatewayIntents = GatewayIntents.AllUnprivileged | GatewayIntents.GuildMessages | GatewayIntents.GuildMessageReactions;
48+
49+
/// <summary>Whether DM'd slash commands are ever allowed.</summary>
50+
public bool AllowSlashCommandsInDM = false;
4851
}
4952
}

0 commit comments

Comments
 (0)