Discord Botで120人が参加するRTA大会のノルマ管理をしてみた話 ~コピペでBotが作れるサンプルつき~

RTAイベント

はじめに

みなさん初めまして。御茶麒麟と申します。

主にドラクエのRTAを中心に活動していまして、先日『身内メンツでDQRTA8作リレー』というイベントの運営お手伝いをさせていただきました。

大会コミュニティ
過去の大会記録(Wiki)

仲がいい人を集めてリレーするこのイベントの特徴は、何より参加人数が多いこと!その人数なんと15チーム120人!


画像:15チームが同時にRTAを行う大会のミラー映像

人がたくさん集まるのは運営冥利につきるのですが、これまで開催してきた経験からめちゃくちゃ大変だと思っていた仕事がありました。

それが『ノルマ確認』と『生存確認』のふたつです。

今回はRTA大会運営のホワイト化とDX化を進めるべく、Discord Botを作ったのでそちらを紹介していきたいと思います。ちなみに当方のスキルは、プログラムは真面目に勉強したことはない一般会社員です。PC関係の調べものに忌避がなく、コピペがうまければできるかなと思います。

 

でもお高いんでしょう・・・?

ご安心ください
全部無料でできます

Botを使ってやりたかったこと(やれること)

結論からいうと、DiscordとGoogleスプレッドシートを連携してデータ管理を自動で行うシステムを作りました。運営の中には、Botはわからないけどエクセルの扱いならできるという人も多かったので、スプレッドシート上でデータを見れるというのは結構大きかったです。

※雑なイメージ図

 

さて、今回の大会を運営するにあたりやりたかったことは下記の通りです。

ノルマ管理

身内リレーでは練習期間に基準タイムを最低1走クリアするノルマを設けています。
ただ、120人もいるとノルマをクリアしたかどうかを1チームずつ毎日チャットを確認するのがそりゃあもう大変。。。
ということで、ノルマを達成したかを自動で判定するシステムがほしかった。

生存報告を自動で記録する

身内リレーでは1週間に1度の生存報告をお願いしていました。
まあ終わってみれば頻度が高くて大変だったという意見もありましたが、過去の蒸発事件、コロナ禍の大会ということもあり今回は1週間という頻度で最後までいかせていただきました。
ただこれも前回まで手動で運営が確認し、しばらく反応がない人に確認を行うという、多大なる運営の労力を使っていました。これも今回は自動化をせねばならぬという使命感がありました。

 

ということでBotを作って全部自動化しました。

ノルマ管理

①DiscordでBot宛にノルマ確認メッセージをメンションで飛ばす

②メッセージを判定して、ノルマ確認メッセージの場合スプレッドシートへ情報を飛ばし記録する

③ノルマタイムがクリアされていた場合自動で返信する

 

生存報告を自動で記録する

①だれかが発言するとそのログをスプレッドシートへ記録する

②毎週日曜日に一番最新の発言が1週間以内かを判定する

③Discordへメンションをつけて投稿する

 

その他機能

おみくじや特定ワードに反応する機能を付けました。生存報告をやりやすくする会話のネタとして一役買っていました。

 

こんな感じで無事Botの導入に成功しました。

途中いろいろ不具合はありましたが、初回にしてはまあうまく使えたのではないでしょうか。

Botの作り方

みなさん結局知りたいのはどう作るか?というところではないでしょうか。

ということでとりあえず作ったやつ置いておきます。同じ機能なら、コピペでそれっぽいところいじれば使えると思います。

プロの方から見るとめっちゃコード汚いと思いますが、コピペの山なので許してください。

Botはこちら

スプレッドシートはこちらこちら

Botの準備

Botはサーバーで常にアクティブにしておく必要があります。
サーバーを作る際に参考にしたサイトは下記の通りです。常にBotをアクティブにしておく用のプログラムなんかもそのまま丸パクリしました。素人でも作れたので本当に誰でも(多分)作れると思います。(作成したBotを常にアクティブにするScriptはこちら

使用した無料サーバーはこちら⇒Glitch

誰でも作れる!Discord Bot(基礎編)

誰でも作れる!Discord Bot(応用編)

 

上の解説サイトからちょっとサイトのデザインが新しくなっていますが、『glitch-hello-node』を選んで作ったと思います。

無料の場合、期間中の稼働時間に制限がありますが、Bot1個動かすだけなら制限に引っかかることはないかなと思います。
ただ、一気にみんながリアクションするとたまに反応が返ってこないことがあるように感じました。時間当たりのリアクション数にも制限があるかもしれないので、超大勢で使うよう場面を想定している場合は、自前サーバーを使ったほうがいいかもしれません。

スプレッドシートとの連携

連携したいスプレッドシートの『Apps Script』へ連携用のコードを入れてます。

※ちなみにスプレッドシートのScriptはここを押すと開く

 

Botから受け取った情報をどう処理しているかの参考サイトも一応貼っておきます。

GASでURLを踏んでスクリプトを動作させたときにパラメータを渡す方法

結局やっているのは、Discordの発言からキーワードを拾って、そのキーワード情報をもったURLを作成、スプレッドシートへ渡して転記させている感じです。

情報を渡す側:Botのコードでいうとこの辺(108行目あたり)

//messageのログをスプレッドシートへ出力
if (message.contet != "") {
//返信者の情報を格納
var name2 = message.member.displayName; //Discordの表示名
var id2 = message.member.id; //DiscordのID
let channelname2 = message.channel.name; //DiscordのチャンネルID

// 形式に添ってspreadsheetに出力する
var url2 = process.env.GAS_URL2;

// spreadsheet URLにパラメータを付加
url2 = `${url2}?name2=${name2}&id2=${id2}&channelname2=${channelname2}`;

情報貰う側:『生存確認用(公開用)』のスプレッドシートのコードで言うとこの辺

function doGet (e){  
 //URLのパラメーターから転記する情報を定義する
  const name = e.parameter.name2;
  const id = e.parameter.id2;
  const channelname = e.parameter.channelname2;
  var time = new Date();
 //発言日時を記憶する
  time = Utilities.formatDate(time, "Asia/Tokyo", "yyyy/MM/dd");
  var GLITCH_URL = "GlitchのURL";

 //A列の一番下のデータが入っている列の1つ下を選ぶ準備
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('転記');
  var nameRange = sheet.getRange('A:A').getValues(); //A列のデータをすべて取得
  var lastrow = nameRange.filter(String).length;
  lastrow = lastrow + 1
 
 //各情報を転記する
  sheet.getRange(lastrow,1).setValue(channelname);
  sheet.getRange(lastrow,2).setValue(id);
  sheet.getRange(lastrow,3).setValue(name);
  sheet.getRange(lastrow,4).setValue(time);

}

 

 

逆にDiscordに対してBotから返信を行う際はスプレッドシート側から情報をまず出させます

情報を送る側:『生存確認用(公開用)』のスプレッドシートのコードでいうとこのへん(長いのでBotとの連携で大事なところを青字にしています)

function postseizon(){

 const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('生存確認');
 var loopraw;
 var loopname;
 var loopid;
 var loopchannnel;
 var jsonarrangement = [];
 var n = 3;
 var GLITCH_URL = "GlitchのURL";

//Botに送る情報を配列を作る

//生存確認で一週間以上反応がない人の情報を配列へ格納する
for(var r = 0 ; r<17 ;r++){
for(var i = 0;i < 8 ; i++){
loopraw = sheet.getRange(n,7).getValue();
if(loopraw == true){
loopname = loopraw = sheet.getRange(n,2).getValue();
loopid = sheet.getRange(n,3).getValue();
loopchannnel = sheet.getRange(n,8).getValue();
jsonarrangement.push([loopname , loopid,loopchannnel]);
}
n = n + 1;
}
n = n + 1;
}


//Glitchへ送る情報を作る 
   var json = {
      'type':'regularconfirmation',
      'debug':'false',
      'content': JSON.stringify(jsonarrangement),
    };
   sendGlitch(GLITCH_URL, json);
}

//Glichへ情報を送る
function sendGlitch(uri, json){
 var params = {
   'contentType' : 'application/json; charset=utf-8',
   'method' : 'post',
   'payload' : json,
   'muteHttpExceptions': true
 };
 response = UrlFetchApp.fetch(uri, params);
}

情報をもらう側:Discordへ実際に発言を送るよう指示をしているのはBotでいうとこの辺

//外部からのリクエストに反応する
http
.createServer(function (req, res) {
 // methodがpostのものに反応させる
if (req.method == "POST") {
var data = "";
req.on("data", function (chunk) {
data += chunk;
});
req.on("end", function () {
if (!data) {
res.end("No post data");
return;
}
var dataObject = querystring.parse(data);
console.log("post:" + dataObject.type);

・
・
・

//Typeがregularconfirmationのものに反応させる
if (dataObject.type == "regularconfirmation") {
var jsonarrangement = JSON.parse(dataObject.content);
var jsonDeployment;
var seizonname;
var seizonid;
var seizonchannel;
var r = 0;

//各配列を読み取り生存報告がない人へメンションを飛ばす
for (r = 0; r < jsonarrangement.length; r++) {
jsonDeployment = jsonarrangement[r];
seizonname = jsonDeployment[0];
seizonid = jsonDeployment[1];
seizonchannel = jsonDeployment[2];

seizonid.toString();
seizonchannel.toString();

client.channels
.get(seizonchannel)
.send(
`<@!${seizonid}>` +
seizonname +
"さんお元気ですか?最近反応がないようで寂しいです"
);
}
}
res.end();
});

 

時間指定でDiscordへ情報を送りたい場合はスプレッドシートのトリガーで時間を指定できます

注意点として、コピペしかできない私がBotを作っていてよくミスったのが、Scriptの中身を更新したのにURLを更新していないパターン。いじったらちゃんと毎回デプロイしてBotの環境設定URLを更新するようにしましょう。

※ここでスプレッドシートへリンクするためのURLを都度作る必要がある

※Bot側のここにURLを入れているので都度更新する

特定ワードに返信する

こちらはBotの中だけで完結しています。

メッセージに『おみくじ』が入っている場合はランダムで何かを返すというシンプルな構造なので、スプレッドシートと連携すれば、もっと複雑に返信も作れると思います。

 if (message.content.match(/おみくじ/)) {
let arr = [
"今日のあなたは超吉!神速のタイムを体現せよ!",

・
・
・

"今日のあなたは超凶・・・バルログ襲い掛かり!ザラキ!ビンゴ!!!",
];
if (message.isMemberMentioned(client.user)) {
var random = Math.floor(Math.random() * arr.length);
var result = arr[random];
message.reply(result);
}
}

応用と今後の展望

特定のワードを拾って記録したり、スプレッドシートでデータ処理したものをDiscordへ返信する機能も実装できたので、結構やりたいことは柔軟に対応できると感じました。

応用例としてはDiscordへ報告したRTAのレース結果やアンケート(ご意見)を自動で転記する、反応してくれた人を集計する、スプレッドシートで整理したデータをDiscordへ呼び出すなどなど・・・

これ以外にも、Googleカレンダーと連携して予定を投稿したりもできましたので、かなり遊べます。IFTTT(なんかいろいろなサイトを連携できる便利なサイト)とも連携できるみたいなので、IFTTTで直接連携できないことも、Botを絡めればDiscordへのアクションの幅をかなり広げられそうです。

やりたいことを探すときに便利なサイト↓
Discord.js Japan User Group

Googleカレンダーとの連携↓
グーグルカレンダーの一週間の予定をDiscordのbotで送信してみた Google Apps Script(GAS)

過去に使ったことがあるIFTTTの機能↓
【Discord】Googleカレンダーと連携してテキストチャンネルにリマインダーを送るBotを作る。【プログラミング不要】
DiscordチャンネルにTwitter投稿を反映させる方法【IFTTT】
「IFTTT」でTwitterとスプレッドシート連携すると、より便利に。

最後に

今回は自分がやったことのメモという意味も込めて、Discord Botを作った話を雑にまとめてみました。大会運営は大変ですが、少しでも楽にできるところは楽にしていきたいものですね!

Bot作ってみたいけど言ってることよくわかんないわ~という方や、横文字ちょっと難しそうだわ~と感じた方はお気軽に私のツイッターにでもご連絡ください。

焼肉1食分で手を打ちましょう。

ではでは次のドラクエRTA大会でお会いしましょう~

コメント

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