「ららマジ」最大の強敵、タイムアウトエラーを倒す

(追記)リライト版を作りました:

eps-r.hatenablog.com

以下の読みづらい話は下書きということにさせてください。


「空の青さを知る人よ」良かったですね。岡田麿里脚本作品に対してはあまり見てない割にちょっと偏見というか、どうしようもない状況からひねり出される、どうしようもない各位の、どうしようもない悪意によって皆が辛くなっていく話……みたいな印象があって身構えてましたが、今回は良くも悪くもなのかカラッと見やすい心地でした。愛の掟で戦うまゆ毛、気高いまゆ毛を君は見たか、神秘のボディが光を放ってる。

今日はアオサでもビーファイターでもなく、この「ららマジを遊ぶ時はチームを減らすと楽になる」というツイートの解説をやります。

先に結論から書いておくと、

  • 使わないチームの編成は最小(先頭ひとり)にする。
  • 先頭ひとりのサブドレスも外しておく。
  • メインドレスのドレスノート解放数が0だと更に軽い。

ひとことで言えば編成キャラのドレスノートを減らしましょう。1.8MBが400KBになる程度には違ってくるはず。

少しデータは増えますが、チーム1の先頭をヘルパー枠(1名)にしてチーム2を常用、残りは解散、という方法でもOKです。

タイムアウトを倒すために

結論は書いてしまったので後はずっと仕組みの話になります。

前置き

「最近ららマジが重いなあ、なぞの通信タイムアウトも多いなあ」と思ってふとネットワークモニタを見てみたら、重いのはサーバやスマートフォンの動作ではなく通信量なのが分かってきました。

特に上のツイートで1.5MBと言っているのが、今回問題にするヘルパー選択画面です。

タイムアウトとはなにか?

HTTPの通信タイムアウトの理由を雑に分けるとだいたい以下の3パターンになります。

  1. 端末がサーバーに要求を送信できなかった、または送信し切れなかった
  2. サーバーが処理を終えられなかった
  3. サーバーの応答を端末が受信できなかった、または受信し切れなかった

ららマジにおいてはひとえに、九割九分圧倒的に「3」で、かつ「受信し切れない」タイプのタイムアウトが発生します。

f:id:appalerm:20191207115847p:plain

f:id:appalerm:20191207115855p:plain

本作のヘビーなプレイヤーであれば一度や二度といわずこのコンボでタイトル画面に戻されたことがあるはず……。

なぜタイムアウトするのか?

「サーバーの応答を端末が受信し切れなかった」。なぜこれが起こるのかというと、ららマジにおいてはひとえに、九割九分圧倒的に、通信サイズが大きすぎるからです*1

特に本作のAPI*2の通信タイムアウト時間はわずか15秒となっていて、量の多いものを少ししか待たないのだから、時間切れにもなります。

1.5MBを15秒間でダウンロードするなら800kbps、1.8MBならば960kbpsの帯域が必要です。これを電波や混雑のせいと表現するエラーメッセージは半分だけ正しくて、通信できているのに帯域幅が足りないからアプリ側の判断で自主的に切ってしまうわけです。

モバイルゲームのくせに、たかがゲーム準備画面にタイトな制約を設けているのは良くないと思いますし(いや、常識的なゲームAPIの通信量なら平然と収まる時間なんだが……)、通信制限どころかちょっとした地下鉄や人混みでゲームが遊べなくなるのは大変厳しいユーザー体験です。何よりこのゲーム、APIのダウンロードタイムアウトからのリトライは例外なくタイトルに戻すようになってるのが渋い。

処方(1) 編成に関わるドレスノートを減らす

ゲーム中のAPIでは通信量が一二を争うほど大きいと思われるヘルパー選択画面については、以下の考え方で受信サイズを概算できます(ヘルパーの内容はほとんど関係ない)。

  1. 編成中メンバーの解放済みドレスノート数に強く影響を受ける。実用的な編成では1チームあたり約160KBを使用し、その大部分がドレスノート(たとえば1個あたり100byteと仮定すると、1名あたり約38KB、1チームあたり約153KB)。
  2. ドレス総所持数に影響を受ける。たとえばドレス所持数が200を超えるプレイヤーは常に150KB以上上乗せされているはず(1着あたり約750byte。ちなみに本作の総ドレス数は300余)。

目安として、ドレスを300着持っているユーザーならフル装備・フル編成時で1.8MB程度の通信量になると予測しています。これをチーム1つに絞れば400KBくらいまで落とせるはずです。

本作のチームと装備の構造を念のためおさらいしておくと、

  • プレイヤーあたり10チームの編成が可能
  • 1チームあたりメンバーは1〜4人
  • メンバーあたり「ドレス(カード)」を最大6着セット可能(メイン1、サブ5スロット)
  • ドレスあたりの成長要素「ドレスノート」を64個ほど解放可能(解放最大数はドレスによって異なる)

というものです。

ドレス1着あたりのノート解放数を64個と仮定した時、チームにぶら下げられるノートの最大は6スロット x 4名 x 10チームで15360個。1個100byteとして1.53MBの通信が発生します。

このノート数を1/10にすることでノートは1536個になり、データとしては1.38MBの削減になります。レイド報酬のために150回も周回していれば延べ通信量などは200MBから変わってくるわけです。

とにかくドレスノートが(表示もしないくせに)通信帯域を圧迫しているため……ここで再掲しましょう。

  • 使わないチームの編成は最小(先頭ひとり)にする。
  • 先頭ひとりのサブドレスも外しておく。
  • メインドレスのドレスノート解放数が0だと更に軽い。

ということをすると少し良くなります。400KBを15秒で落としきるために必要な帯域幅は213kbps。ゲームAPIとしては多い方とはいえまだマシな規模にはなるかと。

処方(2) タイムアウト処理を迂回する

これは最近知ったのですが、通信中にホーム画面などの別タスクに切り替え、受信が終わった頃にゲームに戻るという荒業であらゆる画面の通信15秒制限を無視することができます。

まだるっこしいので個人的には使えませんが、ドレス一覧など重さのどうしようもない画面を低速環境下で乗り切るには有効かもしれません。

チームのドレスノートを減らす。通信が遅いなと思ったら一旦OSのホーム画面に逃げる。これらの技を駆使してタイムアウトエラーをすり抜け、調律にはげみましょう。お疲れさまです。

おまけ

残りは補足と悪口です。

無駄な情報が多い話

そもそもヘルパー選択画面にプレイヤー全チームの詳細は要らなくないですか。なぜ概要でないのか。

画面要素から想像したAPIレスポンス
名前 内容 推定サイズ
プレイヤー情報 ランク
経験値
リフ(コイン)
らら石
選択中チーム番号
ららライフ(イベント時)
ミッション達成情報
1KB
ヘルパー情報 先頭ドレスID
先頭ドレスLv
先頭ドレスイラスト(覚醒前or後)
プレイヤー名
ランク
紹介文
最終ログイン
フォロー関係
512byte x 20
自チーム情報 チームID
チーム内位置
ドレスID
レベル
ドレスイラスト(覚醒前or後)
1KB x 10

大体こんなところかなと思うし、全部合わせても30KBを超えるようには見えません。

これを70倍にするカラクリが先ほど説明したもので、おそらく内訳は下記のようなものです。

通信量から推定したAPIレスポンス(最大1.8MB程度)
名前 内容 推定サイズ
プレイヤー情報 ランク
経験値
リフ(コイン)
らら石
選択中チーム番号
ららライフ(イベント時)
ミッション達成情報
1KB
ヘルパー情報 先頭ドレスID
先頭ドレスLv
先頭ドレスイラスト(覚醒前or後)
プレイヤー名
ランク
紹介文
最終ログイン
フォロー関係
512byte x 20
自チーム情報 チームID
チーム内位置
キャラID
メインドレスID
サブドレス位置・ID
レベル
上記ドレスのドレスノート情報(1個あたり100byte前後、重複する)
最大160KB x 10
プレイヤーの全所持ドレス ドレスID
ドレスイラスト(覚醒前or後)
Lv
EXP
HP、MP、攻、防
上限解放段階、コンボ数、ノート解放数、スキルも?
750byte x 総所持数

推定サイズは全て「およそこのくらいだろう」という曖昧な推測ですが、通信量モニタとにらめっこして以下の挙動は確認できています。

  • チームに配置するメンバー、サブドレス、ドレスノートの数でサイズが上下すること
  • 同じドレスを複数チームにセットしても線形でサイズが増えてゆくこと
  • 同じチーム編成でも、総ドレス所持枚数の異なる別アカウントだと通信量が変わってくること(たとえば、ゲームを始めたばかりの人はダウンロード量が極端に少ない)

追試してみたい人はこの辺を意識しつつ監視するか、あるいはroot取ってパケットキャプチャしてみると良いかと。

この画面のあとステージを始めるときには1チーム+ヘルパー分らしき200KB弱のデータが落ちてくるため、わざわざ先に全ドレスノートと全ドレスのパラメータを要求する合理的な理由がちょっと思いつきません。

開発終盤でゲームデザインか画面設計のどちらかが大幅に変わったとか、全ドレスを含めた複雑なチェックサムを仕掛けているとか、O/Rマッパーの使い方に巨大な課題を抱えていたとか、その手の不合理な理由はあるかもしれません。

通信経路上での圧縮が効いていない話

いちおう通信内容そのものの解体も試みてはいて、Androidエミュレータ(nox)に入れられるパケットキャプチャで分かる範囲だと、HTTPサーバに向けてMessagePackらしき(暗号化)ボディを投げつける「いわゆるソシャゲー」的実装であることまで把握して、中身は読めないなりに満足しました。

本作で使われているHTTP(HTTPS)、Webページの配信にも普通に使われているこの通信仕様にはContent-Encodingヘッダによって通信内容に圧縮をかける仕組みがあり、どうやら本作にも適用されています。

ただし効率はきわめて悪く、圧縮の前に暗号化されているせいで良くて90%程度にしかなりません*3

圧縮とは雑に言えばバイト列あたりの情報量を濃くする仕組みであり、本来「隙間」の多いMessagePackやJSONのようなデータとは相性が良いはずなのに、事前の暗号化処理によって見かけ上の情報量は最大化されるため一転して相性は最悪になります。

Content-Encodingなんか使わず先に圧縮してから暗号化するという処理順ならゲームの快適さは維持できたはずです。データ構造でしくじっていても5%〜10%程度まで縮められれば200KBは超えません。なぜそうできなかったかには大いに興味があります*4

まとめ

ネットゲームは長く続けると摩耗してゆくものだから、運用データが多くなり、セーブデータも多くなり、サーバアプリもクライアントアプリも製作者もプレイヤーも皆が辛くなってゆくことは理解しています。

ただ、少なくともドレス一覧画面やヘルパー選択画面のタイムアウトを回線品質や混雑のせいにするには余りに筋が悪いといいますか……。過剰な帯域幅を要求することと、「電波の良さ」や「通信の混雑」とでは話が違うし、それでプレイヤーをタイトル画面に叩き出すのは道理に合わぬことです。まして所持リソースの多い上客ほど叩き出されやすいのだからたまらない*5

この記事では、電波や輻輳のせいにする前に直すべきところを3つ挙げました。このうちのどれか1つでもうまくやっていれば、ゲームはかなり快適になっていたはずです。

  • APIレスポンスに大量の重複データと不要データを詰め込んでいる
  • 圧縮と暗号化の順序が逆
  • APIタイムアウトが通信量に対して極端に短い(15秒)

まあ、なんでしょうね、天下のGREEでもこのくらいの地雷を同時に踏んでしまうのだと思うとゲーム開発には魔が住むなあというか、今更これらのうちいずれをも直す体力も作れなさそうなアクティブユーザー数という現実もあり、いろいろ厳しそうです*6。ボロクソ言っておいてなんですがメインストーリーのグランドエンディングまで走り切れるよう本当に応援しています。前のレイドは185位でした。

他のドレス系画面の通信量のことや、Androidにプッシュ通知を発生させなくしたこと(出なくなったよね?)、一度セッションが切れると復帰できなくなること、タイトル画面でしか出さないくせに2回連続でPopする異常リソースダウンロードダイアログなど、その他のわんぱくな話はサービスが続いていたら来年の末にでもやりましょう。それではまた。

*1:さすがにサーバ側の帯域を食い潰していることはないだろうが……。

*2:画像や音声、ステージデータなどのダウンロードではない、ユーザーデータを出し入れする手続き

*3:なおデータ構造のくだりではサイズが(特にドレスノートの数に応じて)まっすぐ伸びることが本題なので、暗号化や圧縮の影響で起こる伸び縮みは「まあ誤差だろ」と決めつけて無視しています。

*4:暗号化の前に圧縮をかけてこのサイズになることは流石に無いと思う。そんなことになったらいよいよ中身の想像がつかない。

*5:1Mbit/secの帯域幅は今日日のモバイルアプリケーションが要求するスペックそのものとしては決して無茶でも不思議でもありませんが、但しそれは動画やリアルタイム通信のようにアプリケーションとして必要があればの話です。Webページが通常タイムアウトを15秒などという短時間にしないのは極端なリアルタイム性を要求しないからであって、通信制限下でも大抵のページは待てば開きます。ではららマジはどうか。一人用アクションゲームでステージ中の通信のない本作に帯域幅を要求してよい場面など原則としてありません。サーバエンジニア目線では許容できる接続本数など考えることは諸々あるでしょうが、ログインセッションを断絶させて認証基盤に負荷を掛けてでも守らねばならないのが破綻した初期設計なのだから、このお話はたまらないのです。

*6:同スタジオのアナザーエデンでは通信量の批判を聞かないので今作の反省が生きたのかも知れません。やってないけど。