iT邦幫忙

2024 iThome 鐵人賽

DAY 11
0
Python

用 Python 打造你的 Discord BOT系列 第 11

[Day 11] 擴充套件 (一):Bot 指令框架

  • 分享至 

  • xImage
  •  

介紹完兩種觸發條件,先暫停一下,來介紹一下一個好用的工具:Bot 指令框架。

進度

Discord.py,有內建擴充包 (extension library),對於開發常見的需求會很有幫助。而今天要介紹的這個擴充 ── Bot 指令框架,就是針對前幾天介紹的各種觸發條件 (事件、應用指令) 的擴充,可以幫助開發者加速開發各種指令。

什麼是 Bot 指令框架?

雖然稱呼 Bot 指令框架 (commands framework) 是「指令框架」 (文件上寫的),但其實只是 Client 的 subclass,基本上能對 Client 做的事,對 Bot 也能做。不過,這兩者的差別是,Bot 已經幫忙把某些常見的設定都處理好了,同時,也提供更多在使用上的彈性。

讓我們再回頭看一次之前的 Quickstart

不知道大家還記不記得之前的各版本 Quickstart (Day 04),那時候其實就有看到 bot 指令框架的寫法。這邊幫大家簡單複習一下,下面這兩種寫法其實效果一模一樣:

import discord

intents = discord.Intents.default()
intents.message_content = True
client = discord.Client(intents=intents)

@client.event
async def on_message(message):
    if message.author == client.user:
        return

    if message.content == 'ping':
        await message.channel.send('pong')

client.run('token')
import discord
from discord.ext import commands

intents = discord.Intents.default()
intents.message_content = True
bot = commands.Bot(command_prefix='', intents=intents)

@bot.command()
async def ping(ctx):
    await ctx.send('pong')

bot.run('token')

對照之後,是否覺得 沒有比較沒有傷害 下面這種寫法更簡潔了~

發生了什麼事

來看一下有哪些變化吧!

1. Client 變成 Bot

前面幾行的程式長得差不多,只是在這個框架中,從原本建立 Client 變成建立 Bot

2. 指令前綴

建立 Bot時,除了同樣要設定 intents 之外,還多了一個可以設定指令的前綴的參數 (這是必要參數)。

不能使用 / 作為前綴,不然會與斜線指令衝突。

3. 預設不會對自己做出回應

在 bot 框架中,內建有 message.author 是否為 bot.user (client.user) 的檢查,就不必再寫一遍了。

4. Message 變成 Context

函數的第一個參數 (至少一個) 從原本的 Message 變成了 Context (參數通常會簡寫為 ctx)。

Bot 指令框架的不同寫法

除了 @bot.command() 之外,也可以用 @commands.command() 搭配 add_command 來建立指令。

下面這兩段程式碼的效果完全一樣:

@bot.command()
async def test(ctx):
    pass
@commands.command()
async def test(ctx):
    pass

bot.add_command(test)

在 Bot 設定「事件」作為觸發條件

這個幾乎沒差別,一樣在後面加上 .event 就好了。

@client.event
async def on_ready():
    print('We have logged in')
@bot.event
async def on_ready():
    print('We have logged in')

用 Bot 來寫應用指令

接下來,來看一下如何用 Bot 來寫應用指令 (application command)。

斜線指令 (slash command)

import discord
from discord import app_commands

GUILD_ID = "your guild ID"
MY_GUILD = discord.Object(id=GUILD_ID)

class MyClient(discord.Client):
    def __init__(self, *, intents: discord.Intents):
        super().__init__(intents=intents)
        self.tree = app_commands.CommandTree(self)

    async def setup_hook(self):
        self.tree.copy_global_to(guild=MY_GUILD)
        await self.tree.sync(guild=MY_GUILD)

intents = discord.Intents.default()
client = MyClient(intents=intents)

@client.tree.command()
async def hello(interaction: discord.Interaction):
    """Says hello!"""
    await interaction.response.send_message(f'Hi, {interaction.user.mention}')

client.run('token')
import discord
from discord.ext import commands

GUILD_ID = "your guild ID"
MY_GUILD = discord.Object(id=GUILD_ID)

class MyBot(commands.Bot):
    def __init__(self, *, command_prefix: str, intents: discord.Intents):
        super().__init__(command_prefix=command_prefix, intents=intents)

    async def setup_hook(self):
        self.tree.copy_global_to(guild=MY_GUILD)
        await self.tree.sync(guild=MY_GUILD)

intents = discord.Intents.default()
bot = MyBot(command_prefix="", intents=intents)

@bot.tree.command()
async def hello(interaction: discord.Interaction):
    """Says hello!"""
    await interaction.response.send_message(f'Hi, {interaction.user.mention}')

client.run('token')

這次又發生了什麼事

這次只有一個地方值得講一下

1. 內建 CommandTree

在使用應用指令時,都需要一個 CommandTree 作為應用指令的容器。不過,在 Bot 指令框架中,就不用自己手動建立。

補充一下應用指令 sync 的時機

在查詢網路上其他人的範例或討論時,有一件事蠻多人提到的:不要在 on_ready 時 sync 應用指令。(例如:這篇這篇)

主要的原因是,on_ready 可能會執行不只一次 (文件中也有警告這件事),平時如果只是紀錄個 log 倒也還好,但如果是 sync 應用指令的話,就有可能會有問題了。之所以會說「可能」,主要是因為 global 應用指令其實是有速度限制 (rate limit) 的 (參考官方文件)。

照理說,如果只是在自己的小小測試用伺服器的話,應該不至於會有問題,但還是要盡量養成好習慣XD

比較建議的時機 (事件) 是 setup_hook,它只會觸發一次。

混合指令 (Hybrid command)

最後介紹一個有趣的東西,在 Bot 指令框架中,有一種東西叫做混合指令 (hybrid command)。聽起來很厲害,但其實是一般的文字指令和斜線指令的混合版:它能夠同時設定兩個指令。

因為有使用到應用指令,所以要記得 sync

@bot.hybrid_command()
async def test(ctx):
    await ctx.send("This is a hybrid command!")

基本上只要向上面那樣設定好,就可以同時擁有兩種不同的指令 (但效果一樣)。

不過,我目前是沒有想到什麼特別適合使用混合指令的情況就是了...

小結

今天介紹了第一個擴充套件:Bot 指令框架,讓大家了解如何用它來做到前面幾天所介紹的功能 (同時也快速複習了前面幾天的主題XD)。


上一篇
[Day 10] 應用指令的參數限制
下一篇
[Day 12] 擴充套件 (二):Task
系列文
用 Python 打造你的 Discord BOT31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言