前置き

Unityエンジニアは最近、圧を受けている人が多いと思います。

近頃はバトルロイヤルゲームが流行ってますが、100人マルチプレイを実現しているPUBGFortniteUE4製ですから、会社の偉い人が「こういうの作れないの?」と仰っても、「UE4じゃないとUnityじゃこういうの無理ですよ」と言って誤魔化せていました。

そんな中、Unityで作られた60人マルチプレイのFallGuysが登場してしまいました。こうなるとUnityエンジニアは会社の偉い人から「Unityでもこういうの作れるやんけ!」と詰められてしまいますが、返す言葉もないといったところでしょう。

Unityテクノロジーズもブログ記事とかで「Unityでもこんなすごいネットマルチプレイゲームが作れます!」と積極的に喧伝してます。

Fall Guys が試練を乗り越えて、グローバルに展開できた理由

正直言ってUnityテクノロジーズのこういう態度を見てるとイライラさせられます。「UnityでFallGuysみたいなゲームが作れるよ!」という割には、UnityはFallGuysのような多人数マルチプレイネットワークが作れる基盤を提供してません

(注:その後、MLAPIがUnity公式のソリューションとして採用されたので、この問題は一挙に解決しました)[2020/12/10 追記]

Unityが現在提供してるネットワーク機能はUNetですが、Unityは2018年8月にUNetの段階的廃止を発表しました。ハッキリ言ってUNetは失敗でした。現在は事実上放棄されています。以下の記事ではUNetのサポートは2018.4LTSで2年間提供されると書かれていますが、今は2020年11月ですからUNetは完全に終了しています。

UNet を乗り越え、マルチプレイヤーゲームはさらなる進化へ

さて、この記事では「UNetが廃止される代わりに、次世代ネットワーク機能がすぐに提供されます」という興味深い事が書かれています。次世代ネットワーク機能とは”Unity NetCode“の事を指してると思われますが、この記事が書かれてから2年、NetCodeは全然できてません。”すぐに”って何年後までが”すぐ”なんだよ。

つまるところ、Unityは現在利用可能なネットワーク基盤を何も提供していません。ですのでFallGuysも何らかの独自またはサードパーティのネットワーク基盤を利用してると思います。(具体的に何のネットワークライブラリを使ってるかの情報はありません)Unityは「FallGuysはUnity製!」なんて偉そうに宣伝する資格はありませんよ。それで偉い人に詰められて困るのは我々のような末端のUnityエンジニアです。

例えるなら、自動車会社が売ってもいない車のCMを打ってるようなものじゃないですか?それでお客様から問い詰められて困るのはディーラーです。

まあそれはいいとして、実際Unityには「マルチプレイゲーム作るのにUNetは廃止だしUnityNetCodeはまだできてない!一体どうすりゃいいんじゃ!」という問い合わせが殺到しているようで、(そりゃそうだ)Unityから問い合わせに答える記事が出ています。

Unity のマルチプレイヤー Netcode の移行ガイド

この記事内のチャートを要約すると、「①チートとか遅延が気にならないならUNet+P2P使えば?②そうじゃなければ専用ゲームサーバーが必要。2021年Q2以降ならNetCodeがあるけど間に合わないなら自前で頑張れ。」という感じです。ひでえなあ。

「自前で頑張れ」と言われてもネットワーク基盤を自前でイチから作るのは無理があります。現実的にはサードパーティのネットワークライブラリを使う形になるでしょう。

この記事はいくつかのネットワークライブラリの概観を見て、今Unityでネットワークマルチプレイゲームを作るなら何を選ぶべきか検討してみたいと思います。

UnityのNetworkView(廃止済み)

せっかくなので最初にUnityが提供していて今は廃止されたNetworkViewというネットワーク機能についても書いてみます。

GameObjectにNetworkViewというコンポーネントを貼り付けるだけでネットワークで同期できる、手軽で便利な機能でした。

プレイヤー間の接続は素のP2Pです。プレイヤーの誰か一人がホストになって、他のプレイヤーがゲストとしてそこに接続します。NATを越えるためには基本的にホストはポート開放設定をしておく必要がありました。ホストのAさんとゲストのBさんが一緒に遊ぼうと思ったら、AさんはBさんにLINEなどで事前にグローバルIPと解放したポート番号を伝えないといけないという、プレイヤーとしてはかなり不便な状態でした。

この不便な状況を改善するために、Unityからマスターサーバーというものが提供されていました。自前のサーバー(開発中はUnity公式ホストされたマスターサーバーをデフォルトで利用できた)でマスターサーバーをホストしておけば、ホストのプレイヤーはマルチプレイの部屋を建てた事をマスターサーバーに登録できるようになります。ゲストプレイヤーは今ゲーム内で建ってる部屋の一覧を検索、参加出来て、わざわざゲーム外で連絡しあわなくても簡単にマルチプレイできるようになりました。

マスターサーバーにはもう一つの重要な機能、NATパンチスルーがありました。NATパンチスルーでNAT越えすれば、わざわざポート開放設定を行わなくてもマルチプレイのホストになれました。ただしNATパンチスルーはルータの相性などによっては失敗します。適当ですが7割くらいの環境で成功する感じでしょうか。NAT越えできない人はポート開放するかホストになるのは諦めてゲストで我慢する感じです。

Photon Cloud

Unityのネットワークは元々NetworkViewしかありませんでしたが、いくらNATパンチスルーで7割くらい接続できるようになったとは言え、3割も接続できないというのは問題っちゃ問題です。

ネット対戦がオマケ機能だった頃と違って、ネットワークマルチ前提のゲームでは100%接続できないと話になりません。

そんな中、たしか2013年ごろに登場したのがPhoton Cloudです。
リレーサーバのホスティングとネットワークライブラリが一体になったサービスです。無料プランでは20人まで同時接続できます。

サーバを使ってるといっても、サーバで何か計算処理を行ってるわけではありません。リレーサーバは通信を中継するだけで、誰かが送ったメッセージを他のプレイヤーに送るだけです。WebRTCで言うところのTURNサーバみたいなもんです。なのでネットワーク機能としてはP2Pと変わりません。プレイヤーの誰かが自動的にマスタープレイヤー(ホスト)となります。

リレーサーバを経由すると通信が遠回りになるのでP2Pに比べて遅延が悪化さえします。じゃあ何でP2Pじゃなくてリレーサーバを使うのか?というと、NATパンチスルーだと接続確率は7割程度だったのが、リレーサーバだとほぼ100%接続できるというメリットがあります。

ほぼ確実に接続できるのは大きなメリットですが、同接プレイヤーが増えると利用料金がどんどん高くなるという問題があります。

もう一つのデメリットは、どれだけ高いプランでも、部屋当たりの秒間メッセージ数は500に制限されているという問題があります。もし部屋にプレイヤーが10人いた場合、誰かが1回メッセージを送るごとに9人に送られるので、9メッセージ数を消費します。秒間500メッセージというのは厳しい制限です。
この制限により、実質的にPhotonCloudでのマルチプレイ人数は4~8人くらいで頭打ちになります。

また、サーバー側の処理が書けないので、チート対策などができません。

PhotonはPhoton Cloudとは別にPhoton Serverというものもあります。これは自前でサーバーをホストする必要がありますが、秒間メッセージ制限はなくなりますし、サーバー側の処理も書けます。

ちなみにPhoton CloudはUnityから以下の記事で採点されてます。

自分のゲームに適したネットコードを選ぼう

Photon PUN Unity評価
安定性 ★★★★
使いやすさ ★★★★★
パフォーマンス ★★★
スケーラビリティ ★
機能性 ★★★★

スケーラビリティが最低評価です。やはり秒間メッセージ制限による人数の頭打ちが大きな問題のようですね。使いやすさは星5ですね。たしかにPhotonCloudは簡単に使えます。

モノビットクラウド

モノビットクラウドは使ったことは無いのですが、izmさんの記事が参考になりました。

モノビットエンジンについて調べてみたので書く

要するに、機能的にも価格的にもほとんどPhotonCloudと同様のサービスという事みたいです。

PhotonCloudに比べてのメリットは、秒間メッセージの制限が無い事です。これにより、数人の接続で頭打ちにはならなくなります。

懸念としては、海外リージョンのサーバがどれくらい充実してるか分からないので世界向けのサービスに向かないかもしれないとの事。

とにかく、NetworkViewで確実に接続できないという問題はPhotonCloudのようなリレーサーバで解決しましたし、その次にPhotonCloudでの問題だった秒間メッセージ制限もモノビットクラウドで解消しました。20人くらいでマルチプレイするならモノビットクラウドを使えば問題無さそうな雰囲気です。

UNet(ほぼ廃止済み)

Unityのブログ記事にはこのような記述があります。

ピアツーピア(P2P)トポロジーでは一度に 24 人を超えるプレイヤーを同期しようとすると問題が生じることが多いため、25 人以上のプレイヤーに対応するセッションに関しては、専用ゲームサーバー(DGS)トポロジーへの移行が推奨されます。

https://blogs.unity3d.com/jp/2019/06/13/navigating-unitys-multiplayer-netcode-transition/

PhotonCloudやモノビットクラウドのような、P2P+リレーサーバの構成では、マルチプレイ人数が25人を超えてくると仕組み的にもはや無理があるという事です。

何故なら、ゲームプレイの快適さはホストのPCスペック次第だからです。下手するとホストはスマホだったりするわけで、何十人分もの処理をこなすのは無理が出てきます。

また、クライアントで全てを処理してしまうので、チートし放題という問題もあります。

Unityブログ記事では、問題の多いP2Pから専用ゲームサーバー構成に移行しようと書かれています。

というわけで悪名高いUNetの話です。

UNetはNetworkViewの置き換えとして登場しました。NetworkViewはホストモードとゲストモードの2つのモードで動作してたのに対して、UNetはサーバーモードというのが用意されました。

以前からあったホストモードはサーバ処理しつつも自分もプレイヤーとして参加するモードでしたが、新しいサーバーモードはサーバ処理だけでプレイヤーとしては参加しません。
そんなもん何に使うのか?というと、つまり自前で用意したサーバに、UNetのゲームを入れてサーバーモードで起動して放置しておけば、いつでも誰でもそのサーバにアクセスして遊べるという事になります。

要するにこれが専用ゲームサーバー構成です。マイクラのサーバとかに似てます。

しかし、普通に考えてUnity製ゲームをそのままサーバに置いて起動するなんて馬鹿げた話です。Windowsサーバなんて高いし、GPUが入ってないとUnityゲームは起動できません。

そこでUnityはLinux向けにもビルドできるようにして、ヘッドレスモードでゲームをビルドできる機能も用意しました。UNetサーバーは誰もプレイしないので画面が出るだけ無駄です。ヘッドレスモードだと画面無しでUnityアプリが起動できるので、GPUを持たないサーバでも起動できます。

これで普通のEC2インスタンスなどでもUnityの専用ゲームサーバをホストできるようになりました。

UNetはNetworkViewの時みたいなマスターサーバーは提供されませんでした。今さら3割くらいは接続失敗しちゃうNATパンチスルーなんか使ってもしゃーないからです。

代わりにUNetではPhotonCloudみたいにリレーサーバをホストするサービスが用意されました。しかしこのサービスはかなり遅延に問題があるようです。

専用ゲームサーバ構成を実現したのは画期的ですが、UNetはとにかく問題だらけで将来性も薄いって事で廃止が決定されたので今UNetを使うのはやめた方がいいでしょう。

MLAPI

UNetの代替として頭角を現し始めてるのがMLAPIです。

Unityテクノロジーズの社員の人がほぼ一人で開発してるようです。多分仕事としてやってるんじゃないでしょうか。

かなりパフォーマンスをチューニングしたことで、専用ゲームサーバ構成で最大64人までのマルチプレイが実現できるとの事。FallGuysが60人だから、説明が本当ならいよいよFallGuysを実現できる領域に到達した事になります。

MLAPIと同じようなネットワークライブラリにMirrorというものがありますが、Unityの比較記事ではMLAPIの方がパフォーマンス評価が上回っており、Unityが一番推薦してるのもMLAPIです。

MLAPI用のリレーサーバも用意されてます。GitHubにあるのでこれを自前サーバに置けば、P2P+リレーサーバ構成も実現できます。

ちなみにMLAPIはトランスポート層のコードが何種類か用意されていて、簡単に切り替えられます。デフォルトだとUNetトランスポートが使われていますが、これはUDP通信なので、受信したデータの順番が前後する事があります。順番が前後するとアニメーションの同期が崩れて動きがギクシャクになったりして、「MLAPIってダメダメじゃね?」とか勘違いしてしまいますが、トランスポートを例えばRufflesというものに変えるとReliable UDP通信になってデータの順番も保証されるので問題が起きなくなります。

Photon Quantum

PhotonQuantumはかなり野心的なネットワークサービスのようです。

今まで紹介してきたネットワークサービスでは、基本的な仕組みとしては毎フレーム自キャラの位置を送信して同期するという方法を使ってます。

しかし、よく考えてみると数十人ものプレイヤーキャラを毎フレーム位置を同期するなんて、無駄に通信帯域を消費して、馬鹿げたやり方なのではないでしょうか?

だって、位置なんて同期しなくても、各プレイヤーのコントローラの入力だけ送信すれば、入力が同じなんだから全員の画面が一致するはずじゃないですか?これなら通信量も大幅に減らせます。

一見頭が良さそうなアイデアですが、実はうまく行きません。Unityの物理は入力が同じでも出力が同じとは限らないからです。端末の違い、計算誤差などで段々ズレていってしまい、自分の画面では自分が勝ってるのに、相手の画面では相手が勝ってるなんて事になりかねません。

そこでPhoton Quantumでは独自の決定論的な物理・数学エンジンが用意されてます。どういう意味かというと、このエンジンではどんな環境からでも入力が同じなら出力が一致する事が保証されているという事です。

ですので、先述したような「ネットワークマルチでは入力情報だけを送信し合えばいんじゃね?」論が実現出来ちゃいます。

入力だけを送信し合う事で、チートを抑止する効果もあります。自キャラの座標を改竄したって他のプレイヤー画面では何も起きないからです。

さらに、決定論的ロールバックという機能もあります。普通だとみんなから入力情報が送られてきて出揃うまではシミュレーションのステップを進められませんが、それだと入力が反映されるまでにラグができてしまうので、入力を先読みしてシミュレーションを勝手に進めちゃう事でラグを無くす機能みたいです。

なかなか素晴らしそうなPhoton Quantumですが、Unity標準の物理演算などを全て専用のものに置き換える必要があるので、既存のゲームをネットワーク対応させる時などは作り直しになってしまいそうです。

さらに、どんだけ凄い決定論的ライブラリとは言え、所詮はP2P+リレーサーバ構成なのは変わりません。むしろ各端末がそれぞれ全員分のシミュレーションを実行するハメになるので、負荷が高くてせいぜい32人が限界という感じみたいです。

Unity NetCode

最後に紹介するのが例の、未完成のUnity NetCodeです。

UnityNetCodeの事は、ぶっちゃけよく分かってません。何と言ってもまだできてないので。
しかし、色々と断片的な情報があります。
まず最初に分かってるのは、UnityNetCodeはDOTSしかサポートしてないという事です。DOTSによるパフォーマンス向上がUnityNetCodeの肝みたいです。

UnityNetCodeでは、Photon Quantumのような決定論的ロックステップという機能が実装されており、入力だけを送信するだけで同期できるらしいです。

「え、Unityの物理は決定論的じゃないから無理じゃなかったっけ?」という話ですが、実はUnityはUnity Physicsという新しいDOTS専用物理エンジンを準備しており、UnityNetCodeでそれを利用するようです。Unity Physicsは決定論的です。

UnityNetCodeが決定論的なのは素晴らしい事ですが、「え、じゃあUnityNetCodeって今さらP2Pなの?」という疑問が湧いてきます。専用ゲームサーバ構成は用意されないのでしょうか?

Unite Tokyo 2019でのセッション「Unity Connected Gamesの現在と未来」の動画の3:47あたりからその点に触れられています。

つまり、専用ゲームサーバ構成は「用意したいね」くらいの温度感ぽいですね。現状(2019年10月時点)まだ何も着手してないっぽいです。

Unityのブログ記事によると、UnityNetCodeではいわゆる従来のヘッドレスモードビルドによるサーバービルドとは異なるDOTSサーバーランタイムというものが用意されるらしいです。

どうもこの辺から話が怪しくなってきます。そもそも、決定論的ロックステップなら入力だけやり取りすればよかったのに、専用サーバで演算するならサーバからシミュレート結果を返さないといけないから結局全キャラの座標の同期が必要になるのでは?

UnityNetCodeは元々DOTS限定にする事でハイパフォーマンスを実現するという触れ込みでしたが、最近になって従来のGameObjectもサポートするという話が飛び込んできました。

え?そうなるとUnity Physicsによる決定論的なネットワークという話は崩壊するのでは?

GameObjectでもUnity Physicsが使えるという話もあるから行けるのかな?

【Unity】GameObjectでもUnity Physicsを使う

う~ん、ひょっとしてUnityNetCode周りの話って結構迷走してるんじゃないかと不安になりますね。

Unityは「2021年Q2にUnityNetCodeがリリースされるからそれが使えるよ!」とか言ってますが、本当にそうなら今の時点で一般開発者が普通に使えるベータ版くらいのものが出てきてないと間に合うはずなくないですか?

というか、まだDOTSからプレビューが取れてないのにDOTSのNetCodeがリリースされるわけないですよね。

仮に2021年にUnityNetCodeがリリースされたとしても、最初は相当限定的な機能かつ、まだ不安定なものにならざるを得ないのではないでしょうか。しかも、UnityNetCodeの専用ゲームサーバ構成のサポートはまだ影も形も存在しない状態です。

つまるところ、UnityNetCodeが本当に普通に使えるようになるのは早くても2022年、いや2023年、下手すると2025年とかになってしまう可能性も普通に想像できます。

まあ、今はMLAPIかな…

私も仕事で選定する必要があったので色々とUnityのネットワークサービスを調べてみましたが、結論としてはとりあえず数年間はMLAPI使っとけばいいかな…という気分になりました。

Unite Tokyo 2019の「Unityだったら簡単!マルチプレイ用ゲームサーバ開発 ~実践編~」というセッションではUnityでのマルチプレイの問題が色々と語られていますが、結局この話で採用されてるのは何なのかハッキリ書かれてはいませんが多分MLAPIの事なんじゃないかなと思います。全部MLAPIにある機能についてだし。

ところで専用ゲームサーバってどうやってホストすればいいの?

PhotonCloudなどはクラウドなので何も考えなくて済みますが、UNetやMLAPIでヘッドレスモードでビルドしたサーバービルドは自前でホストしないといけません。

自前でホストするって言っても、どうしよう?
じゃあ、EC2インスタンスを10個建てて、そこにサーバービルドを置いて10個の部屋として運用しましょうか?
でも、全部の部屋が埋まって、もっと沢山のプレイヤーが押し寄せたらどうしよう?どうやってスケーリングさせればいいんだ?

実のところ、それを解決するサービスが存在します。

例えば、AWSのGameLiftです。
GameLiftを使ってサーバービルドをアップロードしておけば、プレイヤーが接続してきた時に空いてる部屋(サーバ)を案内したり、部屋が埋まってたら自動的にEC2インスタンスを生やして新しい部屋を建ててくれます。

上述したセッションでもサーバーのホストにはGameLiftを採用したそうです。

GameLift以外にも、PlayfabやGoogleにも同じようなサービスがありますし、Unityが買収したMultiplayerというサービスも同じ感じです。

ちなみに、FallGuysはサーバーホスティングにMultiplayerを使ってるらしいです。

Mediatonic のハチャメチャなマルチプレイヤーゲームで Unity が大人数プレイをサポート

これらのサービスを使えば専用ゲームサーバをいい感じにホストしてくれるというわけです。

ちなみにGameLiftとか使うとバリバリにAWS課金されまくります。本記事ではゲーム会社が自社開発したネットゲームのサーバを用意する的なユースケースで話を進めてますが、個人制作者が自作ゲームでGameLiftとか使うのはちょっと手に負えなさそうな気がします。

まとめ

Unityでのネットワークサービスの歴史と現状について、色々なサービスを紹介して概観してみました。

Unity公式のネットワークはちょうど今空白期間に突入しており、今「FallGuysみたいなゲーム作って」と言われたらとりあえずMLAPI使うしか無いんじゃないかという結論に至りました。

専用ゲームサーバはGameLiftのようなサービスでホスティングすれば良さそうという事も分かりました。

今後の展望についてですが、今私は実際に仕事でMLAPIで作ったサーバをGameLiftでホスティングしようとしてます。MLAPIは簡単に使えるんですが、GameLiftは結構厄介なうえにネット上にあまり情報がありません。(個人で使うようなサービスじゃないから仕方ない)

今からGameLift使おうとしてる人とかに需要があるかもしれないので、GameLiftを使う上でつまづいた話とかの記事を書こうかなという感じです。