【Discord Bot】情報非対称性を守る!ワンクリックで対象者をVCへ召喚するBotの作り方
目次
概要と目的
- Dread HungerやAmong Usなどの正体隠匿ゲーム、あるいはTRPGにおいて、第三者(コーチやGM)が各ボイスチャンネル(VC)を巡回する際、意図せず他視点の情報(メタ情報)を得てしまうリスクがあります。また、ゲームの初動でBot操作のために立ち止まる行為は「怪しい動き」としてメタ推理の対象になりかねません。
- 本ページでは、これらの問題を解決するため、「プレイヤーが別画面のDiscord上のボタンを1クリックするだけで、待機中の特定の対象者(コーチ等)を自身のVCに強制移動させるBot」の構築手順とソースコードを公開します。
⚠️セキュリティ上の注意
- 第三者が作成したBotをサーバーに導入することは、権限悪用などのセキュリティリスクを伴います。そのため、本システムは完成品の配布ではなく、各サーバーの管理者自身が構築・運用することを前提としてソースコード(設計図)を公開しています。
必要な環境
- 動作環境: Windows等のPC(Bot稼働中は起動しておく必要があります)、またはVPS(レンタルサーバー)。
- Python: バージョン3.8以上。
必要権限
- Botを導入するDiscordサーバーの「管理者権限」。
導入手順
Step 1:Discordの「開発者モード」をオンにしてIDを取得する
- Botに「誰を移動させるか」を認識させるため、呼び出される対象者(ターゲット)のユーザーIDを取得します。
- Discordの左下、歯車マーク(ユーザー設定)を開く。
- 左メニュー「詳細設定」から「開発者モード」をオンにする。
- 呼び出される対象者(ターゲット)を担当する人のアイコンを右クリックし、一番下の「ユーザーIDをコピー」をクリック。
- 取得した18桁の数字をメモ帳などに控えておく(※複数人いる場合は全員分)。
Step 2:Botの作成とトークンの取得
- Discord Developer Portal にアクセスしログインする。(※アンケート画面が出た場合は「スキップ」で問題ありません)
- 右上の 「New Application」 を押し、Botの名前(例:コーチ呼び出しBot)を入力して作成。
- 左メニューから 「Bot」 を選択。
- 【超重要】 画面中段の Privileged Gateway Intents にある以下の3つのスイッチをすべてオン(青色)にし、必ず下部の 「Save Changes」 を押す。
- PRESENCE INTENT
- SERVER MEMBERS INTENT (メンバー移動に必須)
- MESSAGE CONTENT INTENT
- 上部に戻り 「Reset Token」 をクリックして認証を済ませ、表示された長い英数字の文字列(トークン)をコピーして厳重に保管する。(※トークンは絶対に他人に教えないでください)
Step 3:サーバーへBotを招待する
- 左メニュー 「OAuth2」 → 「URL Generator」 を開く。
- SCOPES 一覧から 「bot」 にチェックを入れる。
- 出現した BOT PERMISSIONS(Botの権限)から、以下の3つにチェックを入れる。
- 「チャンネルを表示」 (View Channels)
- 「メッセージを送る」 (Send Messages)
- 「メンバーを移動」 (Move Members)
- 一番下の 「GENERATED URL」 をコピーし、ブラウザの新しいタブに貼り付けてアクセス。
- 導入したいサーバーを選んで追加(認証)する。
Step 4:プログラムの準備と実行
- PCのコマンドプロンプト(黒い画面)を開き、以下のコマンドでDiscord操作用のライブラリをインストールする。
pip install discord.py
- 以下のソースコードをコピーし、PCのメモ帳に貼り付ける。
import discord
from discord.ext import commands
# ==========================================
# 【設定箇所1】呼び出したい対象者のユーザーIDを入力
# 使う部分の 0 を消して、取得した18桁の数字に書き換えてください
# (※使わない人数分は 0 のままで大丈夫です)
# ==========================================
TARGET_IDS = {
"target_1": 0, # ←対象者1のIDを入れる
"target_2": 0, # ←対象者2のIDを入れる
"target_3": 0, # ←対象者3のIDを入れる
"target_4": 0, # ←対象者4のIDを入れる
"target_5": 0, # ←対象者5のIDを入れる
"target_6": 0, # ←対象者6のIDを入れる
"target_7": 0, # ←対象者7のIDを入れる
"target_8": 0 # ←対象者8のIDを入れる
}
# ==========================================
# 【設定箇所2】Botのトークンを入力
# Step2で取得したトークンを "" の中に入れてください
# ==========================================
BOT_TOKEN = "ここにトークンを貼り付けてください"
class SummonView(discord.ui.View):
def __init__(self):
super().__init__(timeout=None)
async def move_target(self, interaction: discord.Interaction, target_id: int):
# IDが0(未設定)のボタンを押された時のエラー回避
if target_id == 0:
await interaction.response.send_message("このボタンにはまだIDが設定されていません。", ephemeral=True)
return
if not interaction.user.voice:
await interaction.response.send_message("あなたがVCにいないため、呼べません。", ephemeral=True)
return
target_channel = interaction.user.voice.channel
target_member = interaction.guild.get_member(target_id)
if target_member and target_member.voice:
await target_member.move_to(target_channel)
await interaction.response.send_message(f"対象者を {target_channel.name} に呼び出しました。", ephemeral=True)
else:
await interaction.response.send_message("指定された対象者は現在VCに接続していません。", ephemeral=True)
@discord.ui.button(label="対象者1を呼ぶ", style=discord.ButtonStyle.primary, custom_id="btn_target1")
async def btn_target1(self, interaction: discord.Interaction, button: discord.ui.Button):
await self.move_target(interaction, TARGET_IDS["target_1"])
@discord.ui.button(label="対象者2を呼ぶ", style=discord.ButtonStyle.primary, custom_id="btn_target2")
async def btn_target2(self, interaction: discord.Interaction, button: discord.ui.Button):
await self.move_target(interaction, TARGET_IDS["target_2"])
@discord.ui.button(label="対象者3を呼ぶ", style=discord.ButtonStyle.primary, custom_id="btn_target3")
async def btn_target3(self, interaction: discord.Interaction, button: discord.ui.Button):
await self.move_target(interaction, TARGET_IDS["target_3"])
@discord.ui.button(label="対象者4を呼ぶ", style=discord.ButtonStyle.primary, custom_id="btn_target4")
async def btn_target4(self, interaction: discord.Interaction, button: discord.ui.Button):
await self.move_target(interaction, TARGET_IDS["target_4"])
@discord.ui.button(label="対象者5を呼ぶ", style=discord.ButtonStyle.primary, custom_id="btn_target5")
async def btn_target5(self, interaction: discord.Interaction, button: discord.ui.Button):
await self.move_target(interaction, TARGET_IDS["target_5"])
@discord.ui.button(label="対象者6を呼ぶ", style=discord.ButtonStyle.primary, custom_id="btn_target6")
async def btn_target6(self, interaction: discord.Interaction, button: discord.ui.Button):
await self.move_target(interaction, TARGET_IDS["target_6"])
@discord.ui.button(label="対象者7を呼ぶ", style=discord.ButtonStyle.primary, custom_id="btn_target7")
async def btn_target7(self, interaction: discord.Interaction, button: discord.ui.Button):
await self.move_target(interaction, TARGET_IDS["target_7"])
@discord.ui.button(label="対象者8を呼ぶ", style=discord.ButtonStyle.primary, custom_id="btn_target8")
async def btn_target8(self, interaction: discord.Interaction, button: discord.ui.Button):
await self.move_target(interaction, TARGET_IDS["target_8"])
class SummonBot(commands.Bot):
def __init__(self):
intents = discord.Intents.default()
intents.members = True
intents.message_content = True
super().__init__(command_prefix="!", intents=intents)
async def setup_hook(self):
self.add_view(SummonView())
async def on_ready(self):
print("------------------------")
print(f"ログイン完了: {self.user.name}")
print("Botが起動しました!")
print("------------------------")
bot = SummonBot()
@bot.command()
@commands.has_permissions(administrator=True)
async def setup_panel(ctx):
await ctx.send("呼び出したい対象者を選択してください。(※このチャンネルは関係者のみ閲覧可能に設定推奨)", view=SummonView())
bot.run(BOT_TOKEN)
- コード内の 【設定箇所1】(呼び出される対象者のID)と 【設定箇所2】(トークン)を自身の情報に書き換える。
- 例:「"target_1": 0, # ←対象者1のIDを入れる」の赤文字部分に収得した呼び出される対象者(ターゲット)1のIDを入れる。
- 例「BOT_TOKEN = "ここにトークンを貼り付けてください"」の赤文字部分に収得したトークンを入れる。
【ボタンの名前(見た目)を変えたい場合】
- Discord上に表示されるボタンの名前を変えたい場合は、コードの下の方にある label="対象者1を呼ぶ" の赤文字の部分を好きな名前に書き換えてください。
- 例:傀儡・狂人・GM・観戦者。
- ※これ以外の部分(btn_target1 や TARGET_IDS など)はシステムが認識するための記号なので変更しないでください。エラーの原因になります。
- ファイル名を bot.py として保存する。
- コマンドプロンプトで python bot.py と入力して実行。「Botが起動しました!」と表示されれば成功。
Step 5:運用方法
- Botが起動している状態で、Discordの任意のテキストチャンネルを開く。
- チャット欄に !setup_panel と入力して送信する。
- Botが呼び出し用のボタンパネルを設置する。
- 以降、プレイヤーはこのボタンをクリックするだけで、待機VCにいる呼び出される対象者を自身のVCへ強制移動させることができる。
ボタン(パネル)を削除・再設置したい場合
- 不要になったボタンパネルは、Discord上でそのメッセージを右クリック(スマホなら長押し)して「メッセージを削除」を選ぶだけで消せます。
- もう一度出したい時は、再度チャット欄に !setup_panel と入力してください。