はじめに
本記事は、discord botでヘルプのコマンドの実装方法を述べたものです。
対象読者
本記事は以下のような方を読者として想定しています。
- discord.pyまたはpycordでbotを作ったことがある(または作っている)
- 自分で良い感じのヘルプコマンドを作りたいと思っている
- コマンドを作るたびにヘルプコマンドを書き直すのが面倒だから楽に作りたいと思っている
- そもそもヘルプの作り方が分からない
また、本記事のコードはdiscord.pyとpycordのどちらでも動くコードのはずです。
いざ作成!
discord.pyとそのフォークしたライブラリのPycordの両方で、ヘルプコマンドを作る専用のclassが用意されているのでそれを利用します。結論から言うと、以下のようなコードで実装できます。型が分かりやすいように、typingモジュールをインポートして型ヒントを記しましたが省略しても構いません。
from typing import Mapping, Optional
from discord.ext import commands
import discord
class MyHelpCommand(commands.HelpCommand):
def __init__(self):
super().__init__(
show_hidden=False, # 隠しコマンドを表示するかどうか
command_attrs={"brief": "ヘルプを表示"} # ヘルプコマンドの説明
)
async def send_bot_help(self, mapping: Mapping[Optional[commands.Cog], list[commands.Command]]) -> None:
"""引数なしでヘルプコマンドを実行したときに表示されるヘルプメッセージ ($helpみたいな)
Parameters
----------
mapping : Mapping[Optional[commands.Cog], list[commands.Command]]
ヘルプのためにユーザーから要求されたコマンドへのコグのマッピング。
マッピングのキーはコマンドが属する Cog です。値がない場合は None になり、そのコグに属するコマンドのリストになります。
"""
e = discord.Embed(title="ヘルプ", description="コマンドの使い方")
cmds = mapping[None] # コマンドのリストを取得 (Cogを使わないのでNoneを指定)
for command in (await self.filter_commands(cmds)): # 隠しコマンドを除外
e.add_field(name=command.name, value=f'> {command.brief}', inline=False)
await self.get_destination().send(embed=e) # ヘルプメッセージを送信
bot = commands.Bot(
command_prefix="$",
help_command=MyHelpCommand(),
case_insensitive=True, # 大文字小文字を区別しない ($help と $Help は同じ)
intents=discord.Intents.all() # botの権限
)
@bot.event
async def on_ready():
"""botが起動したときに実行されるイベント"""""
print("ready")
@bot.command(
name="hello",
hidden=False,
brief="挨拶をする"
)
async def hello(ctx: commands.Context):
"""$hello と実行すると挨拶をするコマンド"""
await ctx.send("hello")
@bot.command(
name="bye",
hidden=True, # 隠しコマンド
brief="別れ挨拶をする"
)
async def bye(ctx: commands.Context):
"""$bye と実行すると別れ挨拶をするコマンド"""
await ctx.send("bye")
bot.run("token") # botを起動
補足ですが、get_destination()
メソッドはヘルプコマンドが呼び出された場所を取得しています。
実行結果
$bye
コマンドを隠しコマンドに設定しましたが、動作自体はします。ただヘルプには表示されません。
おわりに
自身でヘルプのメッセージをあらかじめ作っておいてコマンド実行時に送信する方法も良いのですが、それだとコマンドの機能を変更したときにわざわざヘルプコマンドのソースコードへ戻って書き直す必要があります。コマンドが多くなると管理も大変です。そこで、例に示した通りにコマンドの属性とループ処理を上手く活用することで、コマンドを実装したら同時にヘルプにもそのコマンドが反映されて、ヘルプのメッセージをわざわざ書く必要がなくなります。コグを使えばコマンドをグループ化できるので、より凝ったヘルプを動的にかつ簡単に実装できます。参考になれば幸いです。最後まで読んでくださりありがとうございました。