ローモバはどうやって動いているのか

2022/10/28に公開

世の中には様々な通信方法があり、条件に合わせて適切な通信方法が選択されています。
https://qiita.com/theFirstPenguin/items/55dd1daa9313f6b90e2f

ローモバのようにリアルタイム性が追求され、かつ信頼性が要求される場合、アプリケーションレイヤの無い生のTCPプロトコルが使用されます。

どのような通信を行なっているか、WiresharkPCAPDroidを使って覗いてみます。
こちらは送られてきたパケットの一部です。


204.141.177.168がIGGサーバのIPアドレス、192.168.0.3はスマホに振られたプライベートIPアドレスです。

反転している\x4500から始まる範囲が送られてきたデータです。

まず分かりやすいのは右側のアスキー表示領域です。
明らかに[XZY]ギルドのweobgwさんの情報っぽいです。アカウント名からギルドタグが始まるまでの部分を数えてみると、weobgw.......と13文字であり、ローモバのアカウント名長さの上限とピッタリ一致します。

最初のところに戻りましょう。左側の16進数表記の部分です。
\x4500ってなんでしょう?16進数から10進数に戻すと69になります。
実はこれ、\x45から始まり、最後の\x00までのバイト数と一致するんです。
他の送られてきたデータも同様に調べることで、最初の2バイトがリトルエンディアンでデータのバイト数を表現していることがわかります。

ひとつのパケットに多くの情報を盛り込もうとすると区切りの部分が分からなくなるため、このような仕様となっていると思われます。

さらに読み進めます。
天下り的ですが、その他のパケットと比較していくと次の2バイトがデータの種類(ローモバ専用のプロトコル)を表現していることがわかります。例えば今回の\xac08はマップを見た時のプロトコル、\xbb0bはチャットが送られてきた時のプロトコルです。

ここから先は類推しながら読み進めます。
当時weobgwさんはK829にいました。829は16進数に変換すると33d、リトルエンディアンで表現すると\x3d03です。
ありますね。ギルドタグのすぐ後ろです。

王国番号が見つかったら、次は座標だ!ってなりますよね。
また天下り的ですがこの部分は結構大変です。
残りの部分でわかりそうなところを見ていきましょう。

次に類推できそうな項目は時刻です。コンピュータで時刻を表現する場合、通常はunix時間が使われます。
https://tool.konisimple.net/date/unixtime
執筆時のunix時刻は大体1666793271です。これをリトルエンディアンで表現すると\x373F5963になります。
似たような数字を探してみると・・・見つかりました。
\xb0d23863は日本時間で2022-10-02 08:52:16になります。
一般的にunix時刻はlong型、すなわち8バイトで表現することが多いです。すなわち\x63から続く4つの\x00も合わせて時刻が送られてきていると考えるべきです。

それでは最後に王国と時刻の間に挟まれている部分を見ていきましょう。
\x35022d5602d6
何がなんだか分かりませんね。座標を表現するなら最大1024なのでshort型(2バイト)が2つ(x,y)あれば十分なのになぜか6バイトあります。
もう一度左側全体を見てみると解釈できていない範囲(最初の方)に、同じ\x35\x02が出てきています。

また天下り的になってしまうのですが、ローモバの王国マップはいくつかのゾーンに分割されています。具体的にはX方向に16分割、Y方向に16分割です。前述の\x3502はゾーンを表すIDです。ゾーン内には128個のポイント(座標)が含まれています。続く\x2dがポイントIDです。

マップを見渡した際にローモバアプリはゾーン単位で情報をIGGのサーバに要求します。また、ユーザの見ているゾーン内に変更(城の移動、進軍等)があった場合、ゾーン単位で情報が送られてきます。このため、あまりにもマップを早く移動しすぎるとゾーンの境界を越え、通信が間に合わずに空のマップが表示されてしまうのです。

ゾーンIDからx,y座標を割り出すのは結構大変です。
上記の\x3502は2進数表記にすると
\b1000110101
となります。x方向は1〜4bit目の\b0101、y方向は残りの\b100011になります。
xを5bitシフトすると(32倍すると)160になります。
これにポイントID\x2dの最初の4bitを1bitシフトして得られる26を加え、やっとx座標186が得られます。
yは4bitシフトして560、ポイントIDの5bit目以降を加えて562になります。
最後に今回は必要ないですが偶奇を揃えるためにyの1bit目をxに加えて完了です。

一見複雑になっているだけのように思えますが、このゾーンIDとポイントIDを組み合わせた仕組みを使うと、ドラアリのような小さいマップ、通常の王国よりも広いマップも表現することができます。

難しいところもあったかと思いますが、根本的な部分を理解することで今後の展開を予想したり、バグの原因を推理できたり、色々と発見があると思います。楽しいですね。

Discussion