【CEDEC再演】「スマホ時代のMMORPGを支える技術」講演レポート


# 概要
[【再演】剣と魔法のログレス いにしえの女神 〜スマホ時代の MMORPG を支える技術](http://connpass.com/event/8876/)に参加したのでそのレポートです。
内容としては、CEDEC2014で行われたものの再演。

#剣と魔法のログレスの紹介
## ブラウザ版ログレス（Flash）コンテンツが前身
- ブラウザ版ログレスを、スマートフォン版に移植するのが目的
- ブラウザ版ログレスは、ちょうど今月で三周年

## 移植に関する問題
- そのままの移植だと、開発時にそのままではムリだろうと判断された
- スマホで本格的にMMOPRGが出来る、をコンセプトに移植
- リリースしてまもなく100位以内に

## リアルタイム通信バトル
- 最大5人までのリアルタイム通信
- 同期性の高いバトルシステムが売り

## 充実のコミュニケーション機能
- エモーション機能
- グループチャット
- 自由度の高いアバタオーシステム

# ログレスを支える開発環境
||クライアント|サーバ|内製ツールなど|
|:---|:---:|:---:|:---:|
|プログラム言語|C++11、Lua|C++11、Python|Python,C#,Perl,Ruby,Shell Script|
|ライブラリ・フレームワーク|Cocox2d-x,Boost|Boost,Flask,Google Test|Cocos2d-x,Protocol Buffers, Adobe AIR|
|ツール・データベースなど|Visual Studio 2013,Eclipse,NDK,Xcode|VMware,MySQL,Apache,mod_wsgi|Jenkins,Gerrit,Cppcheck,Redmine|
|バージョン管理|Git|同左|同左|
|外部サービス|GoogleDrive,Trello|同左|同左|

# ゲームクライアントについて
## プロジェクト要件
- スマートフォンで遊べるオンラインゲームをリリースしたい
- リリース時期はなるべく早く！
	- 開発開始は2012年冬
- ブラウザ版ログレスを移植するのが良さそう
	- サーバは使いまわせても、クライアントは完全新規

## クライアントに求められた要件
- TCP通信が可能である
− iOS,Androidをターゲットとしたクロスプラットフォーム開発が可能
- ブラウザ版ログレス用に作成された、豊富なFlashのアニメーションデータを再利用したい
- 大量の2Dオブジェクトが表示可能である
	- その上で快適なプレイを保証する必要がある
- 以上の要件から、Cocos2d-xを採用
	- Unityは選択肢に上がったが、そのときは2Dのサポートがされておらず、今回の要件には向いてないとされた

## Cocos2d-xのメリット
- クロスプラットフォーム開発のサポート
	- Unityに比べると、ミドルウェアやフレームワークレベル程度のサポートにとどまる
	- しかし、クロスプラットフォーム開発をイチから作ることはなかったので十分だった
- 2Dフレームワーク
- ソースが公開されている
	- MITライセンスで公開されている
	- ブラックボックスな部分がないので対策の検討がしやすかった

## Cocos2d-xのデメリット
- Objective-CベースでC++に移植されていた
	- C++の文化と違う部分でコーディングが面倒
	- 最新の3系だとここは改善されているらしい
- UIサポートが非常に弱い
	- カジュアルゲームを作るには十分
	- 本格的なUIをつくろうとすると一から実装することが多かった

## Cocos2d-xを使用したMMOPRGクライアントについて
- Cocos2d-xの参照ポインタを拡張し、利用しやすくした
− バッチシステムの作成
	- AssetManagerは差分更新（ファイル単位）をサポートしていない
	- MMOは週単位でのファイル更新などが頻繁にあるので向いていない
	- 一から実装しなおし
- UIコンポーネントを追加
	- ページャー
	- タブ
	- スクロールなど
- Flashアニメーションプレイヤーの作成
	- Flashで作られたアニメーションをCocos2d-x上でほぼ全て再生できるプレイヤーを実装
	- これのお陰で開発速度が2〜3割上がった
- 内製のネットワークライブラリツールの組み込み

### MMORPGに不可欠なリアルタイム通信の要素
- TCP通信
	- コネクション指向のプロトコル
	- 確実にデータを届けることが可能
	- 通信速度は少し遅い
- RPCの利用
	- TCP接続により、RPCを用いて非同期的に送受信を行う
	- リモートで関数などを呼び出す仕組み
	- クライアントの要求に応じてサーバの結果などを返す際に使用

### 内製ネットワークライブラリについて
- TCP通信のサポート
	- ブラウザ版ログレスでも同じものを使用
- RPCのサポート
	- IDLからRPC定義を生成するツールを内包
	- IDL：インターフェイス記述言語（Interfase Domain Language）
- 自動生成ツールを使うことで、クライアントとサーバの変更を同期できる
	- 例えば、通信規格を変更した時にどちらかを変更し忘れるということがない

### ゲームアセットとゲームデータとの違い
- ゲームアセット
	- クライアントが使用
	- 音楽や画像、アニメーションなど
	- サーバが知る必要のないデータをクライアントにのみ渡す
- ゲームデータ
	- 必要なデータは必要に応じてサーバからダウンロードされる

### ゲームロジックを処理するのはどちらか？
- MMP型のゲームではゲームのルールはすべてサーバに実装される
- クライアントにはほぼゲームロジックは実装されていない
	- 処理するのは、クライアントで完結するものかクライアントで分散処理可能なものくらい
		- タップした場所に自動で経路探索してクライアントで計算など（送信データは目的の座標だけ）
	- ゲーム進行に関係ないUIの切り替えなどはクライアント側で処理
	- 自分と環境がすべて同期していないといけない
		- サーバで処理してクライアントにブロードキャストして同期を実現
		- チート対策などのためにサーバ側で処理する必要がある

# ログレスを支えるサーバ構成
## ログレスの1ワールドの構成と各ノード
- Account
	- ユーザアカウントの管理
	- 複数ワールドが出た場合は、ここだけ他ワールドと共有
- Database
	- ゲームデータの保存
	- MasterとSlaveはMySQLのレプリケーションを利用して構成
- back-end
	- フロントエンド間のデータ同期
- Zone
	- ゲームサーバ間のデータ転送
	- データのリフレクション用途
	- back-endサーバと違い、データベースと直接接続はしていない
- Game
	- ゲームのアプリケーションサーバ
	- ゲームサーバ間はback-endサーバがデータを同期する
- WebAPI
	- APIサーバ
	- RPC用のサーバ
	- Pythonで構築されている
- Client
	- ゲームのクライアント

## サーバ構成
- 冗長化が可能な限り行っている
	- やらないところは諦めて割り切る
	- C++は冗長化するとコストがかかる
- データベースは垂直分割
	- 機能毎にDBを分割
	- Party、Quest、Map、Chatなど
- 水平分割（ユーザ単位分割）は行っていない

# ログレスを支えるチャットシステム
## チャットシステムの要件
- 可能な限り過去までさかのぼってログを見れる
	- →DBに一ヶ月分程度のログを保持
- 自分がオフライン中の間に、ほかプレイヤーが発言したメッセージもログで見れる
	- 通信がどのぐらい切れるか開発中わからなかった
	- 通信が切れると会話が見れなくなるのが辛い
	- →DBに保存されたチャットログをWebAPI経由で取得する
- グループチャットが出来る

## チャットとクライアントの関連
1. 発言するとキャラクターから吹き出しが出る
	- 発言内容をゲームサーバにクライアントが送信
	- 発言時のクライアントとサーバのやりとりはSocket通信
2. フロントエンド（ゲーム）サーバはバックエンドサーバに内容を送信
3. フロントエンド（ゲーム）サーバはDBに送信
4. バックエンドがDBサーバに送信すると、フロントエンドサーバはクライアントに内容をブロードキャスト
	- 受信したクライアントは吹き出しを表示する
5. クライアントは発言内容を、WebAPIサーバを通じてDBから内容を取得
	- チャットログもこの時に取得
	- はDBから取得しているのでTCP通信で実装

なお、チャットに限らずステータス画面の表示などもまったく同じ仕組で実現している

# 直面した問題と、その解決、今後の課題
- 3G回線でのゲームプレイ
	- 具体的な対策というのはないが、特に大きな問題なく動いた
		- 開発の時は意識していなかったが、テストプレイしてみると意外と動いた
	- 回線切断についてはブラウザ版ログレスのページリロード対策のノウハウがほぼそのまま使えた
		- リロードや切断時に画面をリフレッシュするノウハウをそのまま転用
	- ゲームになるべく早く復帰できる、というのを考えていた
		- サーバ上では切断を感知してもユーザのインスタンスをすぐには破棄しない（3分程度保持）
		- クライアントはサーバに再接続する際に、フルで認証を行わずにすむ
		- サーバ上でデータを保持するのは、MMOにおけるキャラクターデータが重いため
- サーバは資産である過去の実装をそのまま使いまわす必要があった
	- 設計が合わない部分でサーバに高負荷問題が起きた
	- テスト時に問題が発覚した（Zoneサーバに想定より負荷がかかった）

## 今後の課題
- クライアントのパフォーマンス・チューニング
	- マップ描画、アバター描画最適化
	- 電池消費量の改善
	- 今はあまり賢い実装をしてない（昔ながらのマップチップ処理）
	- クライアントの処理の6〜7割を食っている
- クライアントの安定化
	- 強制終了の改善
	- フレンドと遊んでいる状態で切断されると、大きなゲーム機械の損失になっている
- 通信量の削減
	- キャリアの通信制限にかかっても遊べるものを目指したい（できるかどうかは不明）
- サーバの1ワールドあたりの同時接続数を増やしたい
	- サーバをなるべく減らして、ユーザ同士のコミュニケーションの機会を増やすのが目標
	- 8ワールド存在するが、1ワールドあたりの同時接続数は実はそんなに多くない
	- ボトルネックはメモリ。CPUなどはそんなに負荷がかかってない

# 質問会
- ログはどのように処理してるか？
	- 1日数Gとか大量のデータになってる
	- データはブルーレイに焼き付けてゲームサーバからは消去する
- 一番つらかったことは？
	- リリースが年末近かったので、サーバの調達が間に合わなかった（会場笑い）
	- エンジニアは正月なかったような…
	- 皆さんもリリースするときは年末は避けましょう
- 今ならUnityとCocos2d-xどっちを選ぶ？
	- それでもCocos2d-xを選びそう
	- ブラックボックス化されているものを避けたい
	- MMOではパフォーマンスを出し切るようにチューニングしたいという思いがある
	- パフォーマンスを出しきらないとユーザにいい体験を与えられない
- チート対策や、実際にあったチートについて
	- スピードハックなどが来たこともある
	- チート対策は気をつけているが、サーバとクライアントの間のラグを利用された攻撃などがあった
	- 攻撃は結構来てる
- 問題が少なかったのはなにか理由がありますか？
	- 経験豊富なエンジニアが多かったので、経験から避けれた部分が多い
	- 冒険をするより、危なそうな部分を避けることが多かった
	- どちらかというと、思ったより問題が出なかったという結果
- 経営面で意識されていることは？
	- DAUを敏感に意識している
	- 課金率などは後からどうにでもなるので、継続率やDAUを意識している
	- エンジニアとしては、離脱ポイントを調べての改善や継続率を伸ばすために面白いゲームにするのが目標

# 所感
MMOPRGのバックエンドからフロントエンドまでを短い時間ながらわかりやすい説明をしていただけました。
スマホのMMORPGはまだ新しい分野で、全体像についての情報はなかなか少ないと思いますので貴重な内容だったと思います。

少人数で距離の近い箱だったこともあり、質問会でもたくさんの質問が飛び出ました（書いたので全部じゃないです）。
講演1時間＋質問会30分という時間でありながら、充実した内容だったと思います。