218 次瀏覽

Discord.NET V3 音樂機器人開發筆記:新增斜線指令與加入語音頻道

接續前篇文章,這次要在 OnReady 中完成斜線指令初始化,並在輸入指令時讓機器人可以進入你所在的語音頻道。

新增斜線指令

斜線指令有分為全域與伺服器兩種,但目前我們僅會使用伺服器版的斜線指令。

我們將要在 OnReady 中新增「play」和「stop」斜線指令,功能分別為加入語音頻道與退出,並且要考慮到多伺服器共用機器人的情況。

操作步驟如下:

  1. 建立 ApplicationCommandProperties 陣列,以方便一次性加入多筆指令。
  2. 使用 SlashCommandBuilder 分別建立 play 與 stop 的指令,WithName 與 WithDescription 是必須的不可省略。
  3. 使用 commands.Add 將命令加入陣列。
  4. 最後透過迴圈讀取 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 判斷來設計。

  1. 使用 cmd.User as SocketGuildUser 來取得伺服器使用者。
  2. 使用 cmd.Data.Name.ToLower() 方法來強制指令轉小寫,免除大小寫差別。
  3. 判斷使用者是否在語音頻道中,如否就直接發送回應並中斷。
  4. 發送加入語音頻道的回應訊息。
  5. 建立新 Task,防止卡到主執行緒。
  6. 使用 VoiceChannel.ConnectAsync 加入語音頻道,並開啟拒聽。
  7. 設計 stop 指令,使機器人退出語音頻道。
  8. 完成。
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)
    {}
}

留言版

發表留言