PR

Discord スラッシュコマンドが2つ表示される原因とは?重複する理由と対処法を解説

Discord

Discord Botを開発していると、

 /dice
 /dice

のように、同じスラッシュコマンドが2つ表示される現象に遭遇することがあります。

特にdiscord.pyでスラッシュコマンドを実装し始めたばかりの頃は、

  • なぜ同じコマンドが2つあるの?
  • 同期ミス?
  • Discordのバグ?
  • Botを再起動すれば直る?

と悩む方も多いでしょう。

しかし実は、この現象の原因はDiscordのスラッシュコマンド仕様にあります。

この記事では、

  • ギルドコマンドとは何か?
  • グローバルコマンドとは何か?
  • なぜ同じコマンドが2重表示されるのか?
  • どうすれば防げるのか?

を初心者向けにわかりやすく解説します。

スラッシュコマンドとは?

Discord のスラッシュコマンドとは、チャット欄で「/」を入力すると表示されるコマンド機能のことです。

例えば、

 /help
 /ping
 /profile
 /music

などがあります。

現在のDiscord Bot開発では、従来の「!help」形式(プレフィックスコマンド)よりもスラッシュコマンドが主流になっています。

理由としては、

  • 入力補完がある
  • 説明文を表示できる
  • スマホでも使いやすい
  • UIが見やすい
  • セキュリティ観点

などが挙げられます。

なぜ同じコマンドが2つ表示されるの?

結論から言うと、原因のほとんどはこれです。

  • ギルドコマンド
  • グローバルコマンド

の両方で同じコマンドを登録しているためです。

例えば、

 /ping

というコマンドを、

  • 特定サーバー用
  • 全サーバー用

の両方で登録すると、Discord側では別コマンドとして扱われます。

その結果、

 /ping
 /ping

のように重複表示されます。

ギルドコマンドとは?

ギルドコマンド(Guild Command)は、特定サーバー限定で使えるスラッシュコマンドです。

例えば、

  • テスト用コマンド
  • 開発中コマンド
  • デバッグ機能

などで使われます。

<余談>「ギルド」とはディスコードBotで「サーバー」のことを意味する単語として使われています。

ギルドコマンドの特徴

最大の特徴は「反映が速い」ことです。

通常、

  • 数秒
  • 数十秒

程度でDiscordへ反映されます。

そのため、

  • Bot開発中
  • 動作確認
  • デバッグ

に非常に向いています。

ギルド同期の例

await tree.sync(guild=discord.Object(id=%GUILD_ID%))

グローバルコマンドとは?

グローバルコマンド(Global Command)は、Botが参加している全サーバーで利用できるコマンドです。

例えば、

 /help
 /profile
 /rank

など、一般公開向け機能でよく使われます。

グローバルコマンドの特徴

こちらは全サーバーへ配布される代わりに、反映が遅いという特徴があります。

Discord側のキャッシュの影響で、

  • 数十分
  • 長いと1時間程度

反映まで時間がかかることがあります。

そのため、開発中にはやや不向きです。

グローバル同期の例

await tree.sync()

なぜ重複表示されるの?

例えば以下のコードを書いたとします。

await tree.sync()
await tree.sync(guild=discord.Object(id=%GUILD_ID%))

これは、

  • グローバル同期
  • ギルド同期

の両方を実行しています。

つまりDiscord側では、

  • 全サーバー向けの /ping
  • 特定サーバー向けの /ping

の2種類が登録されます。

Discordではこれらを「別コマンド」として扱うため、一覧で2つ表示されるのです。

2重表示を防ぐ方法

開発中はギルド同期だけにする

最もおすすめなのがこれです。

await tree.sync(guild=discord.Object(id=%GUILD_ID%))

のみ使用します。

これなら、

  • 反映が速い
  • 重複しない
  • テストしやすい

というメリットがあります。

本番ではグローバル同期だけにする

Botを公開するタイミングで、

await tree.sync()

へ切り替えます。

そしてギルド同期コードを削除します。

tree.clear_commands(guild=discord.Object(id=%GUILD_ID%))
await tree.sync(guild=discord.Object(id=%GUILD_ID%))

これで重複表示を防げます。

既に重複してしまった場合

Discord側に古いコマンド情報が残っていることがあります。その場合は、一度コマンドを削除します。

以下のようなギルドコマンドを削除するシステム管理者専用のコマンドを用意しておくのも良いですね。

@tree.command(name="clear_guild", description="システム管理者専用。(For system developers only)")
async def clear_guild(interaction: discord.Interaction):

    if interaction.user.id not in ALLOWED_USERS:

        await interaction.response.send_message(
            "❌ このコマンドはシステム管理者専用コマンドです。\n"
            "This command is not available",
            ephemeral=True
        )
        return

    await interaction.response.defer(ephemeral=True)

    count = 0

    for guild in client.guilds:
        try:
            tree.clear_commands(guild=guild)
            await tree.sync(guild=guild)
            count += 1
        except Exception as e:
            print(e)
    await interaction.followup.send(
        f"✅ Guild Command削除完了({count}サーバー)",
        ephemeral=True
    )

ただし、グローバルコマンドはキャッシュが強いため、削除後も数十分表示される場合があります。

これはDiscord側の仕様ですので仕方ないです。

おすすめの運用方法

多くの開発者は以下のように使い分けています。

開発環境

ギルドコマンド

本番環境

グローバルコマンド

つまり、

「開発中はギルド同期」
「完成後にギルドコマンド削除 → グローバル同期」

という流れです。

これが最もトラブルが少なくおすすめです。

まとめ

Discordのスラッシュコマンドが2つ表示される原因は、

  • ギルドコマンド
  • グローバルコマンド

の両方で同じ名前のコマンドを登録していることがほとんどです。

Discordでは、

「ギルド用」
「グローバル用」

を別コマンドとして扱うため、同じ名前でも重複表示されます。

対策としては、

  • 開発中はギルド同期のみ
  • 公開時はギルド削除後、グローバル同期のみ

にするのがおすすめです。

特にdiscord.py初心者は、最初はギルドコマンドだけで開発するとかなり快適になります。

なお、余談ですが当方が提供しているbotは

  • 多くのサーバーは、グローバル同期済み
  • 最近導入したサーバーはギルド同期(on_guild_joinを使用)
    • 定期的にグローバル同期を行い、ギルドコマンドを削除するということを、リソースに余裕がある際に手作業で行なっています。

という運営を行なっています。

ご紹介

筆者はDiscordの運営をより良いものにするためのBotを無料公開しています。よければご自身が管理されているサーバーや、参加しているサーバーの管理者に問い合わせて導入してみてはいかがでしょうか。

よくある質問(FAQ)

Q
Discordのスラッシュコマンドが2つ表示されるのはバグですか?
A

ほとんどの場合はバグではありません。

ギルドコマンドとグローバルコマンドを両方同期していることが原因です。

Q
Botを再起動すれば直りますか?
A

直らない場合があります。

Discord側へコマンド情報が登録されているため、キャッシュが残ることがあります。

Q
グローバルコマンドの反映が遅いのはなぜ?
A

Discord側でキャッシュされているためです。

通常は数十分程度で反映されます。

Q
開発中はどちらを使うべき?
A

ギルドコマンドがおすすめです。

反映速度が非常に速く、テストしやすいためです。

Q
本番公開ではどちらを使うべき?
A

一般公開Botではグローバルコマンドが一般的です。

全サーバーで利用できるようになります。

コメント

タイトルとURLをコピーしました