えけけ鯖の技術解説
誰かの役に立てばと思って、実装の際の技術的トピックについて思い出深い部分をメモしておく。
大まかな構成
- EC2 small のリザーブドインスタンスにアプリ+DBその他すべて乗せてた。リザーブ3年前払いで360$、ランニングコストが10~20$程度、平均すると30$/月くらいで動いてた。
- NodeJS(Vanilla JS) + Express
- TSはまだ今ほど覇権ではなかった
- Socket.IO
- 今は廃れているかもしれないが、WebSocketが使えない環境のfallbackをlong pollingで補ってくれる双方向通信ライブラリ。今なら裸のwsでやると思う。
- ゲーム中の通信はすべて双方向通信で、新規接続時には一度だけ過去イベントをすべて送りつける、その後はチャットアプリのブロードキャスト風に新しい会話などは垂れ流すような構成だったはず。
- MongoDB
- 当時はイケてた
- ユーザーデータ、認証、過去ログなどをすべて保存。複雑なトランザクションなども無かったので、ざっくばらんに書き込んでた。
- ちょっと複雑な統計取ろうとすると期待したindexを使ってくれなかったりで、かなり嫌な思いをした。
- Redis
- ところどころで使った気がする
実行中の村はすべてオンメモリ
なぜかいけると思った。人狼ゲームは所詮テキストデータなので、1ゲームが肥大化してもせいぜいキロバイト単位。へんなメモリリークさえ踏まなければ(確か一回だけ踏み抜いたと思う)いけると思った。ゲーム終了時と感想戦終了の二回にわけてMongoDBにまとめて書き込むようにしてたと思う。 このやり方はOOMでクラッシュするとゲーム中のデータがすべて飛んでしまうリスクはあったが、結局最後までOOMで苦労することはほぼ無かった。 でも、これがリスクに見合ったベネフィットがあったかは正直わからん。今なら多分やらないとおもう。
デプロイ戦略(バージョン管理)
ここは結構気が利いたことをやった。 ゲーム画面のURLにはデプロイごとにv0からv15までをループするバージョン番号が追加されていて、ゲーム実行中にデプロイが行われたときにもゲーム開始時のバージョンで起動したプロセスに接続し続ける仕組みだった。ループするのはnginxか何かの設定ファイルで結局ポート番号をハードコードする必要があったから。サーバー1台の中でポートとプロセスを使ってやりくりするため。
アプリの起動時には数字が書いてあるgenerationファイルを読んで、自分があるべきバージョン番号を確認してport5000+vをリッスンする。上限16ってのは確かnginxも使ってたか?そこでポート番号をハードコードしたかったからだと思う。
アプリの前には小さいNodeJS製のリバースプロキシが設置していてあって、URLをパースし、ゲーム画面ならv0~v15をport5000+vに書き換えてリバースプロキシする。それ以外(ロビーやその他画面)は最新へ。
デプロイが走ると、以下の手順でアプリを更新する
generationファイルのバージョン番号をv=((v+1) mod 16)する。- proxyは、ゲーム以外のリクエストは最新のgenerationのポートにリクエストを流す
- 更新前のバージョンのアプリに、SIGTERM(多分。HUPだったかも)を送信
- JSのメインループ側は、SIGTERMを受け取ったら終了準備状態に入る。新規ゲームの開始を拒否、実行中のゲームがすべて終了したらプロセスをexitする
- 新規プロセス起動時には、v.pid(例:1.pid)みたいに自分のジェネレーションのpidを追跡できるようにファイルを書き出してから起動する
こんなかんじの仕組みで、走り始めた村に悪影響などがでないよう保護しつつ、新しい実装をどんどんデプロイしていけた。
UI
ベタ書きのjQueryでよく頑張ったと思う。10年前(!!)まだShadowDOMは発見されてなかった気がする。 チャットのスクロール追随と発言者フィルタには結構な時間かけてパフォーマンスを最適化してた記憶がある。詳細はうろ覚えだが、スクロール位置が末端(最新)かどうか地道に場合分けしつつ、挙動を切り替えてた気がする。フィルタは確か、再レンダリングをしないように全部CSSでまとめたらいきなりスムーズになった。。。んだったかな。よく覚えてないや。
ゲームロジック
人狼ゲーム自体は相対的にはシンプルなルールではあるので、実装には苦労しなかったが、テストが難しかった。結局今でもどういうテストが必要だったか可能だったか答えはわからない。役職を追加するたびに、プレイヤーの皆様になんだかんだ色々迷惑を掛けていた気がする。この辺は将来の課題ですね。
リプレイ機能
えけけ鯖ではゲーム内のすべての記録にタイムスタンプを保存してあって、過去ログをプレイ中と同じUI、同じ速度で再生するという機能があって、これはCOのタイミングや空気感が重要になるチャット人狼において良いチャレンジだったと思う。
その他
- ゲーム終了時のBGM(自作)とアニメーション演出の同期なんかもちょっとした工夫があって気に入っていた。
- mobileは一切対応しなかった。にも関わらずずっとスマホでプレイしているという猛者もいて、人間って凄いって思った
- 一個だけめっちゃ悔しかったのは、デスノート村を実装して大人数集めて開始したのに、いざ始まってみたらUIが参加人数分のアイコンを表示しきれずポシャったやつ。あれは落ち込んだ。
などなど昔語りでした。
Howl/Horkew
懲りもせず人狼関係のプログラムを書いている。
Horkewは、いくつかのライブラリの詰め合わせだが、その中枢というか、それらのライブラリを糊のように繋げるためにHowlというとても小さな言語セットを設計した。
牌譜や棋譜のように、人狼ゲームの展開を記録する「狼譜」を取れるようにするための言語だ。
HowlはHuman-friendly Outline logging for werewolf game Language とかそんなAcronymのつもりだったが上手くまとまらなかった、まあどうでもいい。
チャット人狼をやっていたときにはよく、占い結果などの最低限のメモをメモ帳に書き殴っていた。そのノリで素早くメモを取れることと、必要なゲーム情報を網羅できる表現力を併せ持つように、なるべく表記揺れを許すガバガバなパーサーになった。記号は大体全角でもOKとか。
一通りログを特定の実装に依存せずにテキストとして保存できるようになると、そしてその形式が流通するようになると何ができるようになるだろう。
TLPT ネタバレ感想 #16-10
人狼TLPTアーカイブズ.006 #16:VILLAGE IX 雪の花咲ける村 第10ステージ - ニコニコ動画
クリス!クリス!お前の全盛期は今です!
クリス三兄弟
ソール字ちっさ
メイソン:面目ないウサギ
TLPT ネタバレ感想 #09-13
人狼TLPTアーカイブズ.014 #09:VILLAGE V 冬霧に冴ゆる村 第13ステージ[ヴァルハラ] - ニコニコ動画
ドリスカムトゥルー
安定のハイラム初夜トン
真狂ー真狼狼
コーダよく出れたなー。
スパイクのミスリードが凄まじいwww
TLPT ネタバレ感想 #13-17
人狼TLPTアーカイブズ.017 #13:VILLAGE VII 夏草がそよぐ村 第17ステージ [W]ヴァルハラ - ニコニコ動画
奇跡の真ー狼狼狂陣形からのクリスショー!とにかくクリス!
ハイラムのエンディングも良い。このエンディングはずっとハイラム自身を縛っているような気がする。
クリス:SGとして憤死
メイソン:浦島人狼
ソロ人狼RPG『グノーシア』感想 (真エンドクリア済み)(ネタバレややあり)
公式 http://d-mebius.com/gnosias/
IGNのわかりやすい解説・レビュー https://jp.ign.com/gnosia/36584/review/sf
事前の盛り上がりやリリース延期の紆余曲折などは全く知らなかったです。いろいろあったらしい。この時勢にVitaのDLコンテンツでリリースとのこと。でも頑張ってほしい。すっごい良かったので///
発売時の記事を見かけて(`ェ´)ピャーってなって購入し、20時間近い熱中ののち真エンド到達。Loop147。
ストーリーと構成が良い。〜コマンド選択によるゲーム進行での疑似人狼ゲームを繰り返しつつ全体の物語でのエンディングを目指すグランドデザイン〜
ストーリー全体についてはIGNのレビューにあるように、ゲームシステムとそれを支えるSFギミックがうまく融合していて、しかもとてもきれいに色んな要素を繋げて回収して終わる。これはもう褒めるしかない。
エンディングルートへの突入は見つけるのに苦しんだが、まあ納得というかなるほどねという感じ。
そして真エンドは、エンディング直後にラッキーゲット。これは震えた。「あっ」て気づいたときの衝撃はシュタゲのトゥルー到達の衝撃を超えたかもしれん。。。
【あの謎】はつまりこういうことだったのかと思うと説得力はある。メタいけどねw
イベント発生トリガーとその回収が楽しい。〜廃村イベントおもしろすぎワロタ〜
ループ開始時に配役を選んで人狼ゲームするわけですが、そのときに一定の条件を踏むと(特定のキャラと特定の役職関係になるとか)イベントが開始する。
条件を満たせそうな配役を選んでくれる機能もあるので、ここでの探索要素は薄め。
イベントは、一本道ですぐ終わるものから、特定のキャラとともに生存勝利することでイベントクリアになるものまで様々。多くの場合は、イベント対象キャラと何日か生き延びれば終わるような感じでした。
イベント内容によっては人狼ゲームどころじゃない結末になってしまうものも多く、賛否が分かれるかもしれない。LWがCOして自殺したり、LWでもないのに幕間の雑談中にCOしたり、共有がxxxxxしたうえxxxxxxxしたり。そんなん全部廃村だわ。僕は好きです。
いくつかのイベントははっきりと人狼の役職を意識しているのがあって、具体的には狼と村の組み合わせでの恋人勝利と、狐と背徳者での両生存勝利という難易度きついやつがあった。しかもこの狐、わざと一番吊られやすいキャラ選んでるだろ・・・とにかくすぐ死ぬ。しかも背徳になぜか敵意持って吊りに来る。まじつらかった。
一人用人狼ゲームとしてのグノーシア。〜人狼AIの制限と、RPGとしての人狼〜
人狼シミュレータ部分にも言及しておく。
ルール的には、いわゆる15人普通村(16A)までの、御三家+狂狼+狐が入ったゲームを遊べる。狼以外の役職は一人まで。細かいルールは固定で初日占い結果なし、連続護衛あり。同票時の処理はダブル処刑か処刑なしかを投票して選ぶ。
なぜか狐が人間カウントを持っている。
ゲームの仕様上、主人公が死んだら終了。
説明の難しい部分や設定が煩雑になりそうな要素を極力排除してあって、初心者がとっつきやすくしてある感じ。
変態配役で開始してAIが混乱する様を見るような遊び方はできません。残念。
で、自キャラ含めて全キャラが6種類のパラメータを持っていて、その数値で疑われやすさやスキルの開放が決まり、あまつさえ相手の発言が嘘だという確定直感を得たりする。
自然言語処理はなしで、占い霊能の結果と、だれかを疑うかだれかをかばうかというライン表明のみでゲームを表現している。
NPCのAIは盤面整理と投票によるライン追跡、それとキャラのパラメータとゲーム中にヘイトを上下する行動からくる好感度で構成されているっぽい。
自キャラ含めて全員がロジックのパラメータが低い序盤だと、初心者村の殴り合い以下で、確定白なのに最終日に共有に吊られたりしてVitaを窓から投げ捨てかけた。が、各キャラが(ゲームが進行するとNPCキャラのパラメータも上昇していく)成長すると、ちゃんと破綻を指摘したりされたり、盤面的に怪しい位置を疑ったりするようになる。破綻はコマンドをつかって指摘しないと気づかないキャラもいるっぽいので注意。
なにしろ発言は定型文しかないので、村による推理らしい推理は皆無なのだが、それでもちゃんと人狼してる気分にはなれるので、まあよく出来てると思う。
なお、役職の潜伏についてはシステム的には可能であるにもかかわらず推理AIが対応していない。しかも推理エンジンと進行管理エンジンが密結合しちゃってるのか、狼が占いCO1確してるのを潜伏している真占いの立場で傍観していたら、夜に占い狼が噛まれて死ぬという不具合にも遭遇した><
一応ゲーム内のFAQにも、ちゃんと対抗COを見逃してると「大変なことになる」とは書いてあるんだけど・・・うーん。
しかも、対抗を増やそうとCOを粘っていると、COが続かなかった瞬間に対抗できなくなってしまう(コマンドが消えてしまう)ので、これはちょっと勘弁してほしかったかなあ。
あまりCO順とかを推理要素につかっているように見えないので、普通にゲームする分には対抗が出たら即COするしかないですね。
しかしまあ、対抗がいるのに潜伏する占いとかを考慮すると、プログラムによる盤面整理ってすっごい難しくなっちゃうんですよね。自分もちょっと盤面整理ツール書きかけたけどそのへんの複雑さに辟易したことがあるので、わかるんですよ。わかります。
潜伏役職が生存している想定の場合、ぶっちゃけ何も決められない。常に全員に全役職の想定が残るような感じになってしまうんだけど、これを人間がどうやって処理しているかというと、雰囲気で真占いは潜伏していないって仮定を置いているんですね。で、AIにこの「雰囲気」ってのを教えるのはなかなか難しいので、まあ仕方ないのかなあと。狩りCOが無いのも多分同様の理由かな?俺たちは雰囲気で人狼してる。
で、そんな制限の多いAIと、機械的に設定されたカリスマとか直感とかのパラメーターで戦うわけだが、これが不思議と楽しかった。何故か。
理由は、RPG的な要素だ。NPCも成長するというところも大きい。
ゲーム開始直後の、全員のパラメーターが低い状態って、まじで初心者村そのものという感じなんですよ。
「あの人が一人で喋ってばかりいるから怪しい。吊ろう」みたいな、大昔にみた初心者村のような光景がちゃんと再現されてて、本人はもちろん理不尽な気持ちになったりもする。
で、そこからパラメーターが上がってくにつれて「ちゃんとした」人狼ゲームに近くなっていく。占い結果から破綻を見破ったり、噛み筋とラインをもとに殴ったり。
敵AIの個性もわかってくるので、人物考察によるメタ推理も捗るようになってくる。
初めの方はパラメータで疑われやすかったりするのどうなのって疑問に思ってたけど、敵も味方も成長することで人狼ゲームがじわじわと高度になっていく様子を表現できていて、なるほどなあと思いました。
ちょうど先週から、作業用BGM代わりに人狼最大トーナメントの動画を最初から順番に流してたんだけど、あのレギュラーメンバーが成長し強くなっていく楽しみ、それと同じ感覚をちゃんとグノーシアのNPCたちから感じ取る事ができた。
そういう意味で、一回一回のゲームだけではなく、人狼プレーヤーとしての成長を楽しめる。キャラの成長が、たんなる派手なエフェクトや数字の変化だけではなく、ちゃんと人狼ゲームの内容に反映されて実感できるという点で、しっかりRPGしてる。下手なRPGよりよっぽどしっかり成長を実感できるという。
コマンド選択とパラメータでの殴り合いという、人狼ゲームシミュレーターとしてはかなり厳しい制限を抱えながら、それらの制限を、逆にRPGとして活かしてしまったというのが、グノーシアというゲームなんだと思います。