feature image

2022年3月27日 | ブログ記事

予想外のバグから生まれた、最高に楽しい課題の話

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

新入生の皆さん、どうもこんにちは。logica (ろじか)といいます。
2021年度に入ってからWebエンジニアリングを学び始めた、まだまだヒヨッコのWebエンジニアです。新入生の皆さんと関われることを心待ちにしております。

さて、今年の春休みは、縁あってKLab様主催の「KLab Server Side Camp (第二回)」に参加させていただきました。
この記事はその報告ブログです。

目次

KLab Server Side Camp (第二回) とは

5日間、Pythonでオンライン対戦型音楽ゲームのサーバーサイドを実装する、インターン形式のイベントです。第一回と内容はほとんど同じですので、詳しい内容に興味があれば下の記事を読んでみて下さい。
KLab公式ブログによる第一回のイベント詳細

ゲームのサーバーを書くのは初めてだったり、普段使わないPythonでの実装だったりと不安なところは多々ありましたが、結局のところ最速で実習を終えてしまい、周りにプレッシャーを与えて勝手に申し訳なくなっていました。
結局REST API & SQL慣れみたいなところはあった

本筋の課題であるサーバーの実装はとても楽しく、それについて語ろうかとも思ったのですが、4日目に予想外のバグから「裏課題」のようなものが発生し、仲間と一緒にヒント無しでそれの解決を考える過程が個人的に一番楽しかったので、今回はこれについて語ろうと思います。
本筋の部分に関しては恐らく他の参加者たちがいっぱい書いてくれていることだと思うので、是非「KLab Server Side Camp」で検索して彼らのブログも覗いてみて下さい。

予想外のバグ

幸い3日目まででAPIサーバーの実装が終わっていたので、4日目は丸一日テストプレイとバグ取りをしていました。
4人くらいでワイワイ遊んで意見を交換していると、一人が「通信対戦中に途中抜けできるのヤバくない?」と言い出し、僕たちはその検証に乗り出しました。

どんなバグだったのか

本来「マルチプレイ中は一時停止が無効」と仕様書に書かれていたのに、クライアントサイドの実装ではマルチプレイ中に一時停止・更にはルームの退出までできてしまったバグでした。

次の画像はマルチプレイ中なのですが、ライブ中一時停止ができてしまっています。あきらめるを選択すると途中抜けすることもできてしまいます。

ゲームの仕様

このバグの重大性を理解するために、まずはこのゲームにおけるマルチプレイの流れを見ていきましょう。

まずはホストとなる人が曲を選択してルームを作成します。


プレイする人数が集まったら、ホストが全員のプレイを開始します。

全員分のリザルトがサーバーに送られたのを確かめた後、リザルト画面が表示されます(それぞれのクライアントに、全員分のリザルトが一緒に送られないと正しく表示ができません)。
下図では一人だけですが、最大4人まで表示されます。

問題点

もう皆さんお気づきでしょうか。
全員分のリザルトが送られたのを確かめた後でないとリザルト画面を表示することができないのに、一時停止・退出をしてしまうとリザルトが永遠にサーバーに送られないことがあり得てしまう、というのがこのバグの一番マズいところです。
実際、誰か一人が途中抜けするとその人のリザルトだけが送られず無限待機が始まってしまいました。

もちろん意図された挙動ではないので、一時停止や途中抜けはサーバー側に通知されることがありません。また、ゲームのクライアントにリザルトを非同期で取ってくる機能がない以上、リザルトは全員分を一斉に送らなくてはいけません。だいぶつらい状況です。

僕たちはこの問題の調査・検証をし終えると、これをどうにかサーバー側で対処できないかとアイデアを練りました。

解決策

そうして出された解決策は、リザルト送信にタイムアウトを設けることでした。

必要な処理

Slackのスレッドで話し合い、この問題を解決するためには、
最初に終わったプレーヤーがリザルトを送った一定時間後、その時点でリザルトを送っていないプレーヤーのスコアを強制的に0にする
という処理を行う必要がある、という結論に至りました。

並行処理による解決

タイムアウトを設けるため、Pythonのthreadingを使用した並行処理を行うことにしました。Gopherなので、こういう問題に面した時まずgoroutineを使ったお手軽並行処理が頭にくるんですよね...
Pythonに疎いので、ベストプラクティスだったかどうかはわかりません。
参考にした記事

threadingでは、非常に簡単に別スレッドを建てて並行処理を実現することができます。今回は次のようなコードを書きました。

非常に簡単です。Threadクラスを継承し、メンバ変数を__init__メソッドで設定し、非同期で処理したい内容をrunメソッドに書けば、あっという間に並行処理用のクラスの完成です。

後は任意の場所でこれをインスタンス化し、start()すればOKです。
runメソッドの中身が、非同期に実行されます。

これらを使って、実際に「10秒後にリザルトを送っていないプレーヤーのスコアを0にする」並行処理を、最初に終わったプレーヤーがリザルトを送った瞬間に開始する、という実装をしました。

実際に途中で「諦める」をしてもらった結果...

無事、途中抜けをした人のスコアを0にすることに成功しました!!

インターンを通しての感想

全体を通して面白い課題がそろっており、特に今回語ったバグ解決は非常にエキサイティングな体験になりました。
基本的に実装する内容は普段作っているAPIサーバーと一緒だったけれども、Pythonサーバー・ゲームサーバーの実装の自信がついたのはとてもありがたかったです。今後はオンラインゲーム作成も友人と協力して手を出していこうかな、と思います。

また、最近個人開発ばかりだったので、複数人でワイワイチャットしながらデバッグするのがとても楽しかったです。複数人開発もイイネ。

KLabさん、素敵なインターンをありがとうございました。

おわりに

このように技術系の会社は、「入社希望者に会社の雰囲気を理解してもらう」インターンだけでなく、「自分のスキルを磨く」インターンを開催してくれている場合が多いです!
新入生の皆さんも、「技術を磨くインターン、楽しそうだな~」と思ったら、traPに入って基礎技術を学び、これらのインターンに参加してみると面白いかもしれません。先輩たちが参加したインターンを聞いて飛び込んでみるのもすごく楽しいと思いますよ!

さて、新歓ブログリレー2022、明日の担当はアネモネくんとtoruthiくんです! お楽しみに!

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

20B。何でも屋です。SysAd / CTF / アルゴリズム / サウンド / グラフィック(デザイン部) にいます。

この記事をシェア

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

関連する記事

2022年4月7日
traPグラフィック班の活動紹介
annin icon annin
2022年4月5日
アーキテクチャとディレクトリ構造
mazrean icon mazrean
2022年3月29日
課題・レポートの作成、何使う?【新歓ブログリレー2022 21日目】
aya_se icon aya_se
2021年7月8日
じゃぱりぱーく・おんらいん
suzushiro icon suzushiro
2021年4月18日
ベズー係数とN項の拡張ユークリッドの互除法
0214sh7 icon 0214sh7
2022年4月19日
【入門】JUCEを使ってVSTプラグインを作ろう!!
kashiwade icon kashiwade
記事一覧 タグ一覧 Google アナリティクスについて