この章では艦これを構成する様々なデータがどのように配信されるのか解説します。
データには大きく分けて2つの種類があります。 マスタデータとユーザデータです。
マスタデータは基本的にログイン時にまとめて取得し、 ユーザデータは行動ごとに必要なものを取得します。
ログイン時にロードで長時間待たされるのは、大量のマスタデータを取得するためだといえます。
マスタデータのAPIは全て /kcsapi/api_get_master/
というURLの下にあります。
ログイン時に艦種、艦娘データ、装備、家具 などの固定データをひと通り取得します。
例外はマップに関するマスタデータで、これは出撃のたびに取得されます。
例えば艦種データを見てみるとid=1が海防艦だったり、戦艦が2種類あったり、 なかなか不思議なものを見た気になります。
艦娘のマスタデータは、約50KBある巨大なデータです。 このデータにはやはり不要なデータがたくさん入っています。 初期のデータはなるべく小さく、必要になった時点で他のデータを取ってくる設計にするとかなり小さくなるはずです。
例えば、全員分のドロップ時のメッセージ1が含まれています。 回数的に考えると、戦闘終了時のAPIレスポンスに毎回含めたほうが全体のサイズは小さくなると思います。
他にも図鑑で使うためか能力の初期値が全員分含まれていますが、これも図鑑にアクセスした瞬間に取得するべきです。 一回のログインで一度も図鑑にアクセスしない人のほうが多分多いんだから。
ユーザデータのAPIは全て /kcsapi/api_get_member/
というURLの下にあります。
所持している艦娘、装備、家具や艦隊の情報、レベルや資材の数などが取得できます。
所持している艦娘が全て詰まったデータです。 1ページに表示されるのはたかだか20件くらいだったと記憶していますが、それでも全件取得します。 これを提督の部屋に戻るたびに毎回取得しに行きます。
艦隊編成画面のソート順をグローバルに持っていて、その順でソートされたレスポンスが返ってきます。 艦隊編成画面でソート順を変更すると、全部取得しなおしです。
それぞれの艦のデータは
{
"api_member_id":32377,
"api_id":2,
"api_sortno":347,
"api_name":"\u6dbc\u98a8\u6539",
"api_yomi":"\u3059\u305a\u304b\u305c",
"api_stype":2,
"api_ship_id":247,
"api_lv":77,"api_exp":349951,"api_afterlv":0,
"api_aftershipid":0,
"api_nowhp":15,"api_maxhp":30,
"api_taik":[30,57],"api_souk":[49,49],"api_houg":[53,49], ...
}
のようなデータになっていて、これが全員分配列で並んだデータになっています。
見て解るとおり、ship_id
が指定されているにも関わらず、
艦娘のマスタデータを一切使わずすべて冗長なデータになっています。
この中で必要なデータはid, ship_id, 現在のステータス値だけであることは容易に解ります。
ソート順の変更も、ソートされたidのリストでよいはずです。
もっと凶悪なのが武器データです。 所持している武器を全て取得します。 艦娘の数とは比べ物になりません。 データサイズでおよそ6倍2ありました。 武器を破棄が凄く遅いのは、破棄後に毎回このAPIが呼ばれるためです。
艦娘と同じように全て冗長なデータになっています。 武器は成長の要素がないので、id何番の武器を何個持っているというレスポンスで十分です。 たぶん現在のレスポンスを9割くらい削減できるのではないでしょうか。
初期化処理を最適化してみましょう。 まずユーザデータのうち、レベルや資材数は現状のAPIのままでよいでしょう。
ログイン直後にマスタデータを取得する必要はありません。 最短で提督部屋の画面を出すために、秘書官のIDと内装のIDリストだけを返すAPIを作りましょう。 秘書艦のログイン時ボイスや、内装の画像はIDからurlが決まるようにルールづけしましょう3。 これだけで提督部屋の画面が出せます。たった数キロバイトで実現可能です。
その後おいおいマスタデータや他のユーザデータを取得するようにしましょう。
- とにかくデータ量を減らす
- データの分割・差分取得をする
- 冗長なデータを避け正規化する
- 非同期通信を活用する
中身のコードがわからないので正確なところはわかりませんが、
レスポンスの svdata=
はおそらくグローバル変数への代入のような処理だと想像します。
つまり、APIのレスポンスを受け取るとグローバル変数が書き換えられることになり、
これを上手く制御して動かすには、通信が逐次実行であることが保証されてないといけません4。
「複数のリクエストを同時に出し、返ってきたレスポンスから処理する」という非同期通信の強みが使えないことになります。 さらに、レスポンスを見て新しくリクエストを作ることも難しいので、「必要なデータがなかったら差分取得」みたいなコードも書きにくいのではないでしょうか。