MMORPGをシングルプレイヤーのゲームと分けているのは、目に見えるすべての背後にあるサーバーです。Ancient Online: Remastered開発日誌の第1回となる今回は、私たちがUnreal Engine 5.8によるMMORPGをどのようにつくっているのかを説明します。クライアントとサーバーのあいだで仕事をどう分担しているのか、世界をどうシミュレートしているのか、そして統合されたひとつの世界を、どうやってライブで編集できるようにしているのか。
2つの部品:クライアントとサーバー
Ancient Onlineは、2つの別々のソフトウェアで構成されています。
- クライアントは、Unreal Engine 5.8上でC++で書かれています。描画、音声、インターフェース、入力がその仕事です。
- サーバーはUnrealから独立しており、私たちがC++23でゼロから書きました。ゲームのルールは、すべてここで動きます。
なぜサーバーをエンジンの中ではなく、別に書いたのでしょうか。MMORPGのサーバーに必要なものは、ゲームエンジンに必要なものとは違うからです。グラフィックはありませんが、数千のエンティティ、永続するデータ、長い稼働時間、そして予測可能なパフォーマンスへの要求があります。独立したサーバーであれば、必要な仕事だけを行い、1バイトに至るまで制御できます。
権威サーバー:クライアントを信用しない
私たちの基本ルールはこうです。クライアントは主張し、サーバーが決定する。
- 移動:プレイヤーの入力はサーバーに送られ、サーバーが位置を計算します。クライアントは、サーバーが伝えた位置をなめらかな補間で表示します。そのため、「自分をテレポートさせる」クライアントや壁をすり抜けるクライアントは、サーバーから見ればどこにも進んでいません。
- 戦闘:ダメージ、命中、ノックバックといった結果は、サーバーで計算されます。たとえば、コンボ攻撃が相手をダウンさせるかどうかはサーバーが判定し、その結果を全員に同時に配信します。
- 経済:アイテム、通貨、ショップでの取引は、サーバーとデータベースの上でのみ変化します。
このアプローチの代償は、ネットワーク遅延をうまく扱わなければならないことです。その見返りは、不正がはるかに難しく、全員に同じルールが適用される世界です。
25 Hzのワールドループ
サーバーは、世界を1秒間に25回更新します。各ステップで、モンスターのAI、移動、戦闘、スキルの効果、天候のすべてが進みます。固定ステップによってシミュレーションは予測可能になり、同じ入力が常に同じ結果を生むことが保証されます。
すべてのプレイヤーが、すべてを知る必要はありません。サーバーは世界をグリッドに分割し、各プレイヤーには、その関心領域の中にいるエンティティ(近くにいるもの)の更新だけを送ります。これにより、混み合った街の中でも、ネットワークトラフィックを妥当な範囲に抑えられます。
軽量なバイナリプロトコル
クライアントとサーバーのあいだには、JSONもRESTもありません。すべてのメッセージは、固定レイアウトのバイナリパケットです。これにより、帯域幅とCPU時間の両方を節約できます。新しいシステム(天候、移動、ゲーム内アカウントサービスなど)を追加するときは、それ専用の、バージョン管理されたパケット仕様を書きます。そして共有ヘッダーファイルを使って、クライアントとサーバーが同じ仕様に基づいて動くことを保証しています。
永続化:ゲームを待たせずに保存する
プレイヤーのデータは、PostgreSQLデータベースに格納されます。しかし、ワールドループがステップごとにデータベースを待つのは許容できません。そこで保存は、ライトビハインド方式の永続化としてバックグラウンドで行います。ワールドサーバーが変更をキュー(Redis)に入れ、バックグラウンドのライターがそれをまとめてデータベースにコミットします。ゲームの流れは、データベースの速度に左右されません。
チャンネルとログインサーバー
プレイヤーはまずログインサーバーに接続します。ここでアカウントの認証、キャラクター選択、セッションを扱います。そのあと、4つのゲームチャンネル(CH1–CH4)のいずれかに移ります。チャンネルのリアルタイムの状況は、ゲームサイトのサーバー状況ページで確認できます。
ライブで編集する、統合されたひとつの世界
Ancient Onlineの世界は、ロード画面で区切られた個別のマップではなく、統合されたひとつの世界として設計しています。世界はセルに分割され、ストリーミングで読み込まれます。
世界のコンテンツ(地形、オブジェクト、モンスターの配置)は、コードの中ではなくデータベースに、バージョン管理された状態で保存されています。私たちは、ゲーム内のワールドエディターでこの世界を編集できます。変更はまず下書きで行い、チェックを経てから公開します。公開するたびに新しいバージョンが作られ、クライアントはダイジェストを比較することで、手元の世界データがサーバーのものと一致しているかを検証します。不一致があれば、データが更新されるのを待ってからゲームに進みます。
クエスト:スクリプト言語としてのLua
クエストとNPCの会話は、サーバー上でLua 5.4で書かれています。これにより、サーバーを再コンパイルすることなく、クエストを開発しテストできます。
プレイヤーのメッセージは、私たちのサーバーの外に出ない
ゲーム内チャットの翻訳に、外部の翻訳サービスは使っていません。私たち自身のサーバーで、CPUのみで動くローカルの翻訳モデルを稼働させており、プレイヤーのメッセージが外部のAPIに送られることはありません。こうすることで、異なる言語を話すプレイヤー同士が、メッセージをスタジオの外に一切出すことなく、互いに理解し合えます。
次回は
開発日誌の第2回では、同じ世界をマウス、タッチスクリーン、コントローラーでプレイできるようにするなかで下した判断を取り上げます。スタジオについてはAstronaut Entertainmentとは?を、ゲームそのものについてはゲームページをご覧ください。


