接續前篇文章,這次要在 OnReady 中完成斜線指令初始化,並在輸入指令時讓機器人可以進入你所在的語音頻道。
新增斜線指令
斜線指令有分為全域與伺服器兩種,但目前我們僅會使用伺服器版的斜線指令。
我們將要在 OnReady 中新增「play」和「stop」斜線指令,功能分別為加入語音頻道與退出,並且要考慮到多伺服器共用機器人的情況。
操作步驟如下:
- 建立 ApplicationCommandProperties 陣列,以方便一次性加入多筆指令。
- 使用 SlashCommandBuilder 分別建立 play 與 stop 的指令,WithName 與 WithDescription 是必須的不可省略。
- 使用 commands.Add 將命令加入陣列。
- 最後透過迴圈讀取 client.Guilds 機器人已加入的所有伺服器陣列,呼叫 BulkOverwriteApplicationCommandAsync 將指令資料批次設置。
async Task OnReady()
{
var commands = new List<ApplicationCommandProperties>();
var playCommnad = new SlashCommandBuilder()
.WithName("play")
.WithDescription("Play music")
commands.Add(playCommnad.Build());
var stopCommnad = new SlashCommandBuilder()
.WithName("stop")
.WithDescription("Stop music");
commands.Add(stopCommnad.Build());
foreach (var e in client.Guilds)
{
var guild = client.GetGuild(e.Id);
try
{
await guild.BulkOverwriteApplicationCommandAsync(commands.ToArray());
}
catch (HttpException exception)
{
var json = JsonConvert.SerializeObject(exception.Errors, Formatting.Indented);
Console.WriteLine(json);
}
}
}
F5 建置並啟動機器人後,於 Discord 伺服器中輸入「/」即可找到建立好的斜線指令。

但現在執行指令後不會有任何作用,接下來我們要來撰寫「加入與退出語音頻道」的功能。
設計指令行為
機器人接收到斜線指令後,會呼叫 OnReceiveSlashCommand 方法,我們可以用一個簡單的 switch 判斷來設計。
- 使用 cmd.User as SocketGuildUser 來取得伺服器使用者。
- 使用 cmd.Data.Name.ToLower() 方法來強制指令轉小寫,免除大小寫差別。
- 判斷使用者是否在語音頻道中,如否就直接發送回應並中斷。
- 發送加入語音頻道的回應訊息。
- 建立新 Task,防止卡到主執行緒。
- 使用 VoiceChannel.ConnectAsync 加入語音頻道,並開啟拒聽。
- 設計 stop 指令,使機器人退出語音頻道。
- 完成。
async Task OnReceiveSlashCommand(SocketSlashCommand cmd)
{
var user = cmd.User as SocketGuildUser;
var method = cmd.Data.Name.ToLower();
try
{
switch (method)
{
case "play":
if (user.VoiceChannel == null)
{
await cmd.RespondAsync($"Please join a voice channel");
break;
}
await cmd.RespondAsync("Join the voice channel");
var task = Task.Run(async () =>
{
var audioClient = await user.VoiceChannel.ConnectAsync(selfDeaf: true);
while (true)
{
await Task.Yield();
}
});
break;
case "stop":
await user.VoiceChannel.DisconnectAsync();
await cmd.RespondAsync("Stopped");
break;
}
}
catch (ArgumentNullException)
{}
}