feature image

2025年3月28日 | ブログ記事

【discordgo】ネタバレを気にせず謎解きの感想を言える場所が欲しい!

この記事は 新歓ブログリレー2025 22日目の記事です。

25Bの皆さん、合格おめでとうございます!
23Bの dye (ダイ) といいます。よろしゅう。
去年はB1の振り返りを記事にしていましたが、今年は BOT を作っていきます。
初心者なのであまり刺さないでーー…

はじめに

さて、皆さんは「謎解き」をやったことはありますか?
謎解きとは、「ひらめきを駆使して、与えられた問題を解き進めることで、目標達成を目指す体験型アトラクション」のことです。
ひとくちに謎解きといっても、家で遊べるものや、街を歩きながら問題を解き進めていくもの、実際に部屋に閉じ込められてしまうもの...などいろいろな種類があります。

こうした、多くの謎解きイベントの共通点に、ネタバレの禁止があげられます。
ネタバレを踏んでしまうと、解き方が事前に分かってしまったり、結末を先に知ってしまったりと体験を大きく損なってしまうためです。

するとどうなるか、感想で言えるが大きく限られてしまいます。イベントの中身に触れてはいけないため、「面白かった!」「好きな公演だった!」とか薄っぺらい感想になってしまうわけです。
ですが、既に公演に参加した友達と「どこが難しかったー」とか「ここが好き」とか話したい!( traP では一つのイベントに対して複数のグループができることが多々あります)しかし、大学で会っても他の人がいますし、イベントに参加した人たちだけで集まるのは難しいです。また、オンライン上で会話しようにも、traQ(部内SNS) には公開チャンネルとDMしか存在しません。

そこで今回は Discord のプライベートチャンネルを使って、ネタバレを気にせずに、謎解きの感想を言える場所を作っていきます。

イベント名のロールを作り、そのロール所持者のみが閲覧できるプライベートチャンネルを作ることで求めていた環境を作ることができます。しかし、いちいちロールの管理画面を開いて、ロールを作ってーーーと工程が多く面倒です。
これらの工程を楽にできるBOTを作ることが今回の目的です。

本編

前置きが長くなりましたが、ここからが実装パートです。
Discord BOT は様々な言語で書くことができますが、今回は Go を使っていきます。
環境構築はなろう講習第一部のテキスト等を参考にするといいです(なろう講習は traP 内で行われる、初心者向け講習の一つ)。

BOT の設定

では、Discord の BOT を作っていきましょう。
まずは、discord.dev にアクセスして、New Application をクリックし、BOT名を入力すると、My Applications に追加されます。追加されたアプリケーションを選択してください。

image-1-2

左側から Bot を選択し、トークンを取得します。Reset Token を押すと、確認ののちトークンが表示されます。後で使うのでどこかにメモしてください(再表示されません)。また、トークンは絶対に公開しないようにしましょう。

image-2-2

次に、OAuth2 で権限の設定をします。
OAuth2 URL Generator から bot を選択し、下にスクロールして必要な権限をチェックしましょう(権限は後で設定することもできます)。権限は必要最低限にすることをおすすめします。
そして、一番下の GENERATED URL をコピーしてアクセスすることで、Discord サーバーに招待することができます(管理者権限が必要です)。

image-3-2
image-4-1

コードを書く

go で discord BOT を作る際は、discordgo が便利です。
ドキュメントコードサンプルを参考にコードを書いていきましょう。

↓のコードを拡張していきます

package main

import (
	"log"
	"os"
	"os/signal"
	"syscall"

	"github.com/bwmarrin/discordgo"
	"github.com/joho/godotenv"
)

func main() {
	err := godotenv.Load(".env")
	if err != nil {
		log.Fatal(err)
	}
    
    // TOKEN は先ほど取得した文字列
	TOKEN := os.Getenv("TOKEN")
	
	dg, err := discordgo.New("Bot " + TOKEN)
	if err != nil {
		log.Fatal(err)
	}

    // ... はイベントハンドラ
	dg.AddHandler(...)
	dg.AddHandler(...)

	dg.Identify.Intents = discordgo.IntentsGuildMessages | discordgo.IntentsGuildMessageReactions

	err = dg.Open()
	if err != nil {
		log.Fatal(err)
	}

	log.Println("Bot is running")
    
	sc := make(chan os.Signal, 1)
	signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
	<-sc

	log.Println("Bot is stopping")

	err = dg.Close()
	if err != nil {
		log.Fatal(err)
	}
}

今回の BOT は

機能を作りました。

ここからは実装していくうえで困ったことを話していきます。
コードの全文を上げるのは長くなるので git リポジトリ を見てください(Go 初心者なのでコードが汚いかも...)。

m.Content が空

症状: 完成版には残っていませんが、送信されたメッセージの内容を取得(MessageCreate)しようとしたとき、内容(m.Content)が空になる。

解決法: discord.dev の bot から、Privileged Gateway Intents を有効にする。

コマンドが反応しない

症状: スラッシュコマンドはサジェストが出るようになっているが、自作コマンドがその候補に出てこない

解決法: ApplicationCommandCreate の第2引数(GuildID)を空文字列にすることで、グローバルコマンド(どのサーバーでも使えるコマンド)になるが、反映に時間がかかる。GuildIDを設定すれば即時反映されるが、そのサーバーでしか使うことができない。

チャンネル名がうまく取得できない

症状: アルファベットを含むイベント名を入れると、参加通知が送られない。

解決法: Discord のチャンネル名はアルファベットが自動的に小文字に変換されてしまう仕様が原因。
イベント名からチャンネルIDを検索するときに、イベント名を小文字に変換することで解決した。

注意点

Discord のプライベートチャンネルはロールによる閲覧権限をつけることができますが、サーバー所有者、管理者はすべてのチャンネルを見ることができます
そのため、サーバー所有者は自分の参加していないイベントのチャンネルを見ないようにする必要があります。自分はサーバー所有用にアカウントを新しく作り、ログアウトしました。

完成

招待チャンネルを設定して...イベント名を入力して...
image-5-1
参加した人がリアクションを付けると...
image-6-1
そのイベントのチャンネルに招待される!
image-7-1

おわりに

いかがでしたか?
前から興味があったBOT制作をこの期にやってみました。
謎解きもBOT制作も、興味を持ったらぜひ挑戦してみてくださいねー

明日はの担当は kamecha さんです。お楽しみに~

Dye icon
この記事を書いた人
Dye

23B情報工学系 AtCoderやってます

この記事をシェア

このエントリーをはてなブックマークに追加
共有

関連する記事

2021年8月12日
CPCTFを支えたWebshell
mazrean icon mazrean
2021年5月19日
CPCTF2021を実現させたスコアサーバー
xxpoxx icon xxpoxx
2024年6月21日
ハッカソン参加記 4班"Slide Center"
Alt--er icon Alt--er
2023年7月15日
2023 春ハッカソン 06班 stamProlog
H1rono_K icon H1rono_K
2024年3月15日
個人開発として2週間でWebサービスを作ってみた話 〜「LABEL」の紹介〜
Natsuki icon Natsuki
2023年10月20日
DIGI-CON HACKATHON 参加記事「Comic DoQ」
mehm8128 icon mehm8128
記事一覧 タグ一覧 Google アナリティクスについて 特定商取引法に基づく表記