前置き
タイトルの通り、今回の記事は結論ありきです。
私はこれからの時代はゲームも多人数マルチプレイが当たり前になると思ってますが、マルチプレイゲームにはネットワーク部分の実装であるネットコードが当然必要になります。
ネットコードというのは単にプレイヤー同士がデータを送受信できればそれでOKというものではありません。
プレイヤーに快適なマルチプレイを提供するには、膨大な量のノウハウと技術が注ぎ込まれた強いネットコードを用意する必要があります。
マトモなネットコードの開発と言うのはもはやUnityでサクッとゲームを完成させたいだけの個人開発者や小規模チームの手に負えるものではありません。
私が今回の記事も含めてこれからいくつか記事を書いて主張していこうとしてる論旨は、「ネットワークマルチのゲームを作る時は、チームに専門家がいない限りはもはや自力で開発するよりプロが作ったゲームテンプレート使っといた方が良い」という話です。
話を分かりやすくするために、Unityでネットワークマルチゲームを作りたいと思ってる開発者のAさんがいるとしましょう。
もしもAさんが、将来ネットコードの専門家になりたいというなら、苦労してでも自力でネットコードを開発すべきでしょうが、単にゲーム作りたいだけなら、素直に売ってる既製ネットコードを購入した方が無難だと言えます。ネットコード開発はむやみに大変だからです。
そもそも論として、Aさんはネットワークマルチのテストが可能な環境を持っているのでしょうか?個人で家で開発してるとしたら、どうやってインターネット越しのマルチプレイをテストするのでしょうか?既製のネットコードはすでに沢山のユーザーが使っており、不具合が報告されるたびに修正されています。つまり、既製ネットコードを正しく使ってる限りは自分でテストするまでも無く高品質なマルチプレイが保証されるはずです。
自力でネットコード開発した方が良いかもしれないケースがあるとすれば、Aさんの開発チームにたまたまネットワークゲームの専門家がいる場合くらいでしょうか。
専門家って例えば誰?と言われると、例えば「オンラインゲームを支える技術」の著者みたいな方ですかね。
「でも、チームに専門家がいない場合に既製ネットコード使ってて不具合出たらどうやって直すの?」と思われるかもしれませんが、それはネットコード開発元のサポートに問い合わせするしか無いですね。サポートが死んでたら一巻の終わりなので、サポートが手厚そうなネットコードを選択した方がいいでしょう。
その辺は、言うたらUnity使ってる時点でUnityの不具合出たらバグ報告してひたすら修正されるのを待つことしかできないのでそれと同じ事だと思いますね。
さて、ネットコードと言われてもゲームジャンルごとに話が異なるので、今回の記事では分かりやすい例として格闘ゲームについての話をしてみたいと思います。
なぜ格ゲーか?というと、格ゲーは2人のプレイヤーが殴り合うゲームなので、100人バトロワとかと比べて比較的話がシンプルなので、とりあえず最初という事で格ゲーの話からやっていきます。
たとえば、開発者のAさんは、PUNの入門記事を読んで、これでネットワークマルチの格闘ゲームが作れるぞ!と意気込んで自力でゼロベースでネットマルチ格ゲー開発を始めたとします。
ここで問題なのが、Aさんはネットコードについては初心者なので、PUNの基礎だけ知ってイケそうな気がしちゃってますが、初心者であるがゆえにネットコードのあまりに闇が深い落とし穴に気付けていない事です。
「まあまあ、最初は誰だって初心者なんだから、一度は自分でやってみて、失敗したらまたやり直せばいいじゃない。」と思われるかもしれません。
しかし、これがまたネットマルチ開発の闇なのですが、ゲームの開発中は自分のPCのローカル内で遅延ゼロ、パケット損失ゼロの環境でしかテストしなかったりするので、ゲームが全部完成するまでネットコードの問題に気付かなかったりします。
3年かけて格ゲーを完成させてしまって、Steamなどで販売してみて、そして実際のプレイヤーのインターネット環境でプレイされて初めて全ての問題が噴出してしまうかもしれません。
そこで初めて貧弱な自作ネットコードのマズさに気付いても、手遅れではないでしょうか。完成したゲームのネットコードを後から既製の物に差し替えようとしても、ネットマルチのゲームロジックというのはネットコード基盤の上にべったり乗っかっていて、ほぼ差し替え不可能で、全部作り直すしか無かったりします。
そういう訳ですので、私はことネットコードについては、「まずは自作してみてダメだったらやり直せばいい」論については、上手く動かない事に気付いた時には手遅れになりがちなので、リスクが大きすぎると思ってます。
「でも初心者ゆえに罠にハマってしまうんだったら、最初から専門家になるまで勉強してからじゃないんとネットマルチのゲーム作っちゃダメなの?」と思うかもしれませんが、別に強いネットコードが自作できるくらいまで勉強する必要はありませんが、少なくとも適切なネットコードの選択ができるくらいにはざっとネットコードの概要だけでも把握しておくと良いかと思います。
私も全然ネットコードの専門家ではありませんが、最近は趣味と仕事を兼ねてネットコードについて色々と調べてます。
初心者の方でも罠を踏まないで済むくらいの情報を提供できればと思って今回の記事を書いてます。
Universal Fighting Engine 2(UFE)について
さて、Unityで有名な格ゲーのネットコードというと、アセットストアで売ってるUniversal Fighting Engine 2(UFE)が有名ですね。
値段の異なる色んなバージョンが売っててややこしいのですが、値段と機能の比較表はこんな感じです。
59ドルのライト版から99ドルのベーシック版に上げると、高度な敵AIが使えるようになるようです。
ベーシックから199ドルのスタンダード版に上げると、ネットワークマルチができるようになります。
スタンダードから349ドルのプロ版に上げると、”ロールバック”のネットコードが使えるようになります。今回の記事では重要なポイントです。
そして、プロからソース版に上げると、ソースコードにアクセスできるようになります。
親切な事に、下位バージョンから上位バージョンへは差額でアップデートできるはずです。
UFEの例えばプロ版349ドルという値段は、アセットストアのアセットの値段として考えるとメチャメチャ高いように見えるかもしれませんが、ネットコードの値段として考えるとメチャメチャ安いです。
格ゲーの有名な既製ネットコードとしてはGGPOというものがありますが、これのライセンス料は公開されてないので分かりませんが、恐らく桁違いに高かったはずです。(ただしGGPOは2019年に無料オープンソース化されました)
ちなみに、この記事を書いてる時点で、ちょうどUFEのライト版とスタンダード版とプロ版が半額セールになってます(7/6まで)
さて、あらかじめ断っておきますが、私はUFEを実際に触った事はありません。
それでも、開発者Aさんと同様の立場で自作ネットコードとUFEどっちにすべきか?という判断の話くらいはできると思います。
とりあえず、UFEのプロ版のストアレビューに目を通してみました。
おおむね好評みたいです。機能面で不満を言ってる人はあまりいないようですが、ドキュメントとサポートが不足している事について不満がある人が一杯いますね。
サポートが不十分な可能性…これはぶっちゃけ不安要素ですね。
レビューの次はスペック、機能面に目を向けてみます。
UFEは高機能な格ゲーエンジンですが、今回の記事ではネットコード周りについて重点的に確認しましょう。
↓UFEのネットコードについてのドキュメントはこちらです。
http://www.ufe3d.com/doku.php/global:netcode
これによると、まずUFEは独自の決定論的物理学が実装されているようです。さらに、遅延ベースのネットコードと、プロ版以上で使えるロールバックネットコードの2種類のネットコードが使えて、それらを組み合わせる事もできるそうです。
素晴らしいですね!
実際の通信についてはIPアドレス直打ちの素のP2PまたはPhoton Cloud(PUN)の2種類が選べるようです。
いきなりよく分からん用語を並べられても、何がすごいのかよく分からないかもしれませんが、これについては後で解説したいと思います。
UFEの機能面もわかった所で、次は、「そんで実際にUFE使って作られたゲームってあるんだっけ?」という点を調べてみましょう。
私がググった限りでは、残念ながらUFEが実際に売られてるゲームで使われてる例は一つしか見つかりませんでした。
それは、Fight of Godsです。
世界中の宗教の神々がバトルするという、ネタ感満載のゲームですが、中身はかなり真面目な作りだそうです。Steamのリリース日は2019/03/28と書かれてます。UFE製だけあってちゃんとネットマルチに対応してます。Steam以外にも、Switch版、PS4版、さらにアーケード版も発売されているそうです。
かなりちゃんとしたゲームのようですね。
チラッとSteamのレビュー欄を見る限りでは、ネットマルチに対して不満を書いてる人は見当たりませんでした。これは快挙だと思います。まあ、ネットマルチに対応したのがかなり最近らしいのでレビューで触れられてないだけかもですが。
UFEの実績がこのゲームしか見つからなかったのは残念ですが、UFEでどんなゲームが作れるのか知りたい方はとりあえずUFEを触る前にこのゲームを遊んでみておくと良いのではないでしょうか。
さて、UFEがどれくらい良さそうなのか?について、アセットのレビュー、機能スペック、採用実績の3つの観点から眺めてみましたが、いかがでしょうか?
「いい所もあるけどサポートがダメらしいし分からないな」って感じでしょうか。まあ私もそう思いましたが、少なくともネットコードの機能については私は素晴らしいと思いました。
何と言ってもロールバックメカニズムを搭載してる所がすごいです。
ロールバックって何なの?何がすごいの?という所を次から話していきます。
GGPO(Goodgame peaceout)について
さて、格ゲーのネットコードには大まかに遅延ベースのものと、ロールバックのものがあると分かりました。
どっちがどうなの?と言う話の前に、一旦、有名な格ゲーネットコードの一つであるGGPOの話をしたいと思います。
↓GGPOの開発者のインタビュー記事がこちらにあります。
かいつまんで内容を書くと、GGPOを開発したトニーさんは、元々格ゲー大好きでした。
カプコンが2005年ごろにネットマルチに対応したスト2を発売してくれて、トニーさんは大喜びでした。「これでアーケードじゃなくても家でネットマルチでスト2対戦できる!!」
しかし、実際にネット対戦してみると、ラグが相当ひどくてマトモに遊べませんでしたので、トニーさんは落胆しました。
さて、一旦インタビュー記事の内容から離れますが、当時の状況について考えてみます。
当時は格ゲー作ってるのは日本のゲーム会社だけで、格ゲーのネットコードは大抵が遅延ベースだった感じだと思います。(遅延ベースがどういうものかは後で説明します。)
ここでポイントになるのは、何故トニーさんの手元でマトモに遊べないような問題を、発売に至るまで日本のゲーム会社が気付けなかったのかという点です。
先ほどのAさんの例では、ローカルPC内でしかテストしなかったのが原因でしたが、カプコンみたいな立派なゲーム会社はさすがにもっとちゃんとテストしてるハズで、例えば開発者同士が自宅からインターネット対戦してみて問題ないか確認するくらいはしていたはずです。
“とはいえ”、所詮は日本の国内同士での通信だっただろうと思われます。
国内のpingの速度を今測定してみましたが、ウチから北海道でも22msで、福岡でも21msです。
pingは通信の往復にかかった時間なので、片道なら半分、つまり私が北海道の人と対戦したら、パケットが相手に到達するまでに11msしかかかりません。
60fpsのゲームならフレーム時間は16.6msなので、遅延はたったの1フレームに収まります。
私はあまり格ゲーをやらない人間なので適当ですが、1フレームの遅延ならほぼ気にならないでしょう。その場でローカルマルチで遊んでるのと同じプレイ感で遊べるはずです。
これが当時の日本のゲーム会社が格ゲーのネットコードは別に遅延ベースで問題無いだろうと考えた理由だと思います。つまり、国内でテストしてる分には全く問題なく快適に遊べるから、問題が発覚しなかったのでしょう。
一方、アメリカでプレイした場合はどうなるでしょうか。
アメリカは国土が広いので、西海岸から東海岸までのpingは67msくらいかかります。これだと、パケットが相手に到達するまでに2フレームかかります。
さらに、日本とアメリカ間でプレイしたらどうなるでしょうか。pingは130msくらいに達してしまうらしいです。
これだと、パケット到達は4フレームもかかります!
4フレームも遅延すると目に見えて反応が遅れるのが分かって、格ゲーみたいにタイミングがシビアなゲームだと相当ストレスが大きくなってくると想像できます。
つまり、当時の格ゲーのネットコードが遅延ベースで良しとされていたのは、国内で遊ぶ分には問題なかったからで、でもワールドワイドで発売してみたら無視できないくらい遅延が大きいケースがあって、快適に遊べなかったという事です。
格ゲーマーにとっては光は遅すぎるという話がありますが、そういう事ですね。
はてさて、トニーさんのインタビュー記事の内容に話を戻します。
スト2のマルチプレイにガッカリしたトニーさんは、自分だったらもっといいネットコードを書けるかもしれないと思ってGGPOの開発を始めました。
GGPOには”ロールバック”というアイデアが搭載されていました。
遅延ベースだと、pingが高い対戦相手の場合は、スティックを倒してからキャラが動き出すまで何フレームも待つハメになってイライラしますが、ロールバックだとネットマルチにも関わらず、スティックを倒した瞬間に遅延ゼロで自分のキャラが動きます。
まさに魔法のような技術です。
トニーさんはこのような素晴らしいGGPOを開発してゲーム会社に売り込み始めて、今ではカプコンやバンナムの多くのゲームがGGPOによるロールバックネットコードを採用しています。スカルガールズも採用してます。
ちなみにGGPOはそれなりにライセンスが高額で、ライセンス料が高くて採用できないゲームもあったようですが、2019年にGGPOはMITライセンスでオープンソース化されました。
これにより、ますます多くのゲームがGGPOを採用していくかもしれません。
そうして、トニーさんは快適なネットマルチで格闘ゲームを遊べるようになったとさ。
めでたしめでたし。
ネットマルチ対応格ゲーを作るための前提条件とは?
諸々の説明が終わった所で、実際の格ゲーネットコードの話に入っていきます。
というか、こちらに素晴らしい格ゲーネットコードの解説記事がありますので、こちらを元に解説する感じです。↓
まず、遅延ベースだのロールバックだのの以前に、実装しておかなければならない前提条件が存在します。
それは、ゲームを決定論的に実装しておかなければならないという事です。
決定論的実装については以前に書いたブログ記事でPhoton Quantumの説明で出た話ですが、まさにあれと同じ話です。
決定論的とはなにか?というと、”入力が同じなら、出力が同じであることが保証されている”という事です。
Unityで普通にゲームを作ってると、決定論的な実装にはなりません。
何故なら、まずUnityの物理エンジンが決定論的ではないからです。実行環境によって、同じ入力でも微妙に出力が違ってきたりします。
それと、Unityは可変フレームレートがデフォルトです。つまり、Time.deltaTimeを使って、フレームレートが上下しても1秒間のプレイヤーの走る距離が変わらないように実装できます。
これは便利ですが、決定論的な実装とは相性悪いと思います。決定論的実装だと固定フレームレートが必要になるんじゃないかな。
[追記 21/07/04]
決定論的実装にとってもう一つの大きな問題、”浮動小数点問題“もあります。
ゲームを完全に決定論的に実装したつもりでも、float(浮動小数点)を使ってる時点で、もはやCPUアーキテクチャが異なるマシン間では誤差が出てしまうので正確に同期できなくなる問題です。
つまり、x86のCPUを搭載したWindowsマシンとARMのCPUを搭載したWindowsマシンでは同期できなくなるかもしれません。
ただ、コンパイラでIEEE754準拠モードを強制してコンパイルすれば問題を回避できるらしいです。
とは言え、それはfloatの計算の最適化を無効にする事を意味するので、浮動小数点の演算速度がガタ落ちしてしまうようです。
↓詳細はこちらの記事をご参照ください。
Floating Point Determinism
さらに、コンパイラ云々の話はC++とかの場合に可能な話で、一般的に言ってC#だとどうしようもないみたいです。何故ならC#がビルドして生成するのはネイティブコードじゃなくてILという中間言語であって、ゲームを実行するマシン上のそれぞれのJITコンパイラがILを解釈して実行するという仕組みだからです。参考↓
Coercing floating-point to be deterministic in .NET?
[追記ここまで]
ゲームが決定論的実装だと、例えばゲームのリプレイ機能なんかも簡単に作れるようになります。
東方の原作シューティングゲームでは、リプレイ機能がありますよね。あれのリプレイデータの中にあるのは、プレイヤーがどのフレーム数でどのキーを入力したかの入力情報だけです。
決定論的実装なので、入力情報さえあれば、何度でも同じゲーム内容をシミュレートできるという訳です。
東方も固定フレームレートなので、処理落ちすると普通にゲームが遅くなりますよね。
ちなみに、決定論的実装ではランダム要素は使えません。ランダム要素があると毎回結果が変わってしまうからです。ただし、乱数テーブルを使えば疑似的にランダム機能が使えます。
さて、それでどうしてネットマルチの格ゲーには決定論的実装が必要なんですか?と言う話です。
ゲームが決定論的なら、マルチプレイで送るデータはお互いの入力データだけで済みます。
決定論的じゃなかったら、お互いのキャラの現在の座標やステータス、アニメーション、とにかく同期に必要な全てのデータを毎回送るハメになります。
相手に最速でデータを送りたければ、データは小さい方が良いです。
それに、入力じゃなくお互いの状態を送る方法だと、チートできてしまいます。送信データを改竄して、常にHPマックスにすれば、自キャラを無敵にしたりできちゃいます。入力データだけをやり取りする方法ならそういうチートは不可能になります。
さらに言えば、決定論的なゲームであれば、自由にゲームを巻き戻したり、進めたりできるはずです。
「もしも相手が4フレーム前にパンチボタンを押していたとしたら、現在の画面はこうなってるハズ」みたいなシミュレートが自由にできます。
このようなシミュレート機能がロールバックネットコードには必須になります。まあ遅延ベースなら必須では無いかも。
なんか色々とややこしい話が出てきて混乱されている方もいるかもしれませんが、要するに私がここで言いたい事は、ネットマルチ格ゲーは前提として決定論的に実装する必要があるけど、Unityで決定論的実装するのはそれだけですでにかなり難しいという事です。
でも、UFEを使えば決定論的実装がされているので心配無用です。
遅延ベースのネットコード
さて、例のトニーさんを落胆させた遅延ベースのネットコードを見ていきましょう。
まあこれはシンプルなんで難しくないです。
例えば、私とAさんがネット対戦するとします。
私からAさんまでのパケット到達に3フレームかかるとします。まあ予備のバッファとして1フレーム足しておいて、4フレームの遅延を設定しましょう。
すると、単にゲームの進行は私の入力から4フレーム遅延して実行されます。
それだけです。
ちなみに格ゲーの通信はシビアなのでTCPだとお話にならないのでUDP通信である事が前提中の前提です。
とはいえ、もし私が送信したパケットが相手に届かずに損失してしまったらどうしますか?
いくら入力だけ送り合えば同期できる決定論的ゲームでも、肝心の入力が送れなかったらもう同期が崩壊しちゃうんじゃないですか?
心配ご無用です。それなら、いつ損失してもいいように、常に過去5フレーム分とかセットで入力データを送ればいいのです。どうせ入力データのサイズは小さいので5倍になっても大したことありません。
これなら、あるフレームのパケットが届かなくても、次のフレームに過去のフレームのデータも含まれてるのでシミュレートできます。
ただし、届かなかったフレームはシミュレートが進められないので画面が止まります。
↑この図を見ると分かりますが、まずパケットが届かなかった方の画面が1フレ止まってから、辻褄を合わせるために次のフレームでもう一方の画面も1フレ止まります。
ちなみに、画面を止めないテクもあります。
例えば、届いたパケットを常に1フレ待ってからシミュレートするというテクです。
そうすれば、どこかでパケット損失が発生しても、すでにその次フレームで表示すべき入力情報は届いているので、画面を止めなくて済みます。
これらの工夫でパケット損失の問題は上手い事行きそうですが、実は他にも問題があります。
処理落ちの問題です。
相手側のプレイヤーで処理負荷が高まって1フレームだけフレーム落ちしたらどうなりますか?
ちゃんと相手がフレーム落ちした事を検知しないと、自分と相手のゲーム内容が段々ズレていってしまいます!
これを検出するためには、送信パケットに自分のゲームの進行フレーム数を含めておきましょう。
例えば、自分の進行フレーム数が100フレだとします。それで設定した遅延数が4だとすると、相手から今回届くのは96フレのパケットのハズです。
でも、95フレのパケットが届いてしまいました!
この場合、相手がフレーム落ちしたらしいな…と分かります。しゃーないので、こちらも1フレ画面を止めてあげて辻褄を合わせる必要があります。
さて、元記事によると遅延ベースのネットコードの技術はこんな感じです。色んな工夫してるんだな~と感心しますが、とは言え結局4フレーム遅延しちゃうのはどうにもできてません!
というわけで次は魔法のテクノロジーであるところのロールバックネットコードを見てみましょう。
ロールバックネットコード
ロールバックのネットコードは遅延ベースの遅延を何とかするために考案されました。
ロールバックでは、なんと遅延ゼロでのゲームプレイが実現できます。
しかし、そうは言っても私とAさんの間にはパケット到達までに3フレームの時間差が発生するはずです。一体どういう事なんでしょうか?
↑ロールバックのメカニズムについて解説するために、こういう状況について考えてみます。私と対戦相手のAさんは、0フレーム目にお互いまったく同時にパンチボタンを押したとします。この画面は私の側です。私側のゲームは私がパンチボタンを押した事は認識していますが、相手がこのタイミングで何を入力したのかは当然ながら不明です。
↑2フレーム目です。私のパンチモーションが発生中ですが、相手の0フレーム目の入力は未だにこちらに届いてません。なので相手は棒立ちのままです。
↑3フレーム目です。ここでようやく相手の0フレーム目の入力が届いて、実は相手も0フレーム目にパンチボタンを入力していた事が分かりました。すると、今まで棒立ちだった相手がいきなりノーモーションでパンチ出してます!相手の動きが飛んだように見えますが、たしかにお互いが0フレーム目でパンチボタンを入力していたので、この時点で辻褄が合いました。これがロールバックです。
ちなみに相手の画面でも全く同じ現象が起きてるハズです。
一体何が起きたかと言うと、実は相手の入力が届いた時点で、ゲームは内部的に0フレームまで巻き戻されました。それで、まるで過去を改変するがごとく、相手が0フレーム目にパンチボタンを押していたとしたらどうなっていたか?という前提でまた現在のフレームまでシミュレートを進めます。すると、このような結果になるという訳です。
このように、相手の入力データが届くたびに常にゲームが過去に巻き戻って(ロールバック)再シミュレートされるのがロールバックネットコードです。
ちなみに、相手の最後の入力データから現在フレームまでの相手の行動は適当な予測で埋められます。予測って何か?というと、そんなに難しい予測はしてないと思います。相手が何も入力してなければその後も何も入力してないだろうと予測するし、相手が左にスティック入れっぱなしだったらその後もずっと左にスティック入れっぱなしだと予測されるでしょう。
さて、このロールバックネットコード、遅延ゼロで遊べるのは素晴らしいですが、常に過去改変されちゃうのが問題と言えば問題です。
例えば、自分がヒット発生まで時間がかかる大パンチを放ったとします。相手は棒立ちです。
これは完全にヒットして相手が吹っ飛んだ…やったぜ!と思ったら次の瞬間吹っ飛んでたのは自分だった…なぜ?
実はこちらが大パンチを打った直後に相手が発生の速い小パンチを打ってきていたからでした。
みたいな理不尽なケースも高pingの環境では起こり得ますね。
そうは言ってもロールバックネットコードの恩恵は大きいようです。
↓こちらでは何故か近所の友達との間のpingが300ms超えな環境での遅延ベースネットコードのゲームプレイとロールバックのゲームプレイを比較しています。
違いは一目瞭然ですね。
もっとロールバックネットコードについて詳しく知りたい方はこちらの動画がオススメです。
自力でこれを実装できるだろうか?
さて、ここまででネットマルチ格ゲーを作るために必要な、決定論的実装の話や遅延ベースネットコード、ロールバックネットコードの話を見てきました。
これらの技術について、この話を聞いて「なるほど、分かった」と言ってゴリゴリ実装できる人がいたとしたら相当な天才なのではないでしょうか。
そのような天才以外の方は、とりあえず自前で作るよりUFE2使ってみるのが無難な気がしますね。
UFEならこれらのややこしい技術が全部搭載されてますからね。
ちなみに、UFEのドキュメントによると、ロールバックネットコードに遅延ベースを組み合わせるのが一番良さそうだと書かれてます。何故かというと、高ping環境の対戦だと、かなりのロールバックが発生してしまうので、対戦相手がワープしたりする現象が頻発してしまうので、それなりに遅延も入れておくことで理不尽なワープ現象を軽減できるからとの事です。
しかし、UFEで私が一つ気になるのは、通信方法が素のP2P以外ではPUNしか用意されてない事です。
PUNを使うと必ずリレーサーバを経由して通信してしまうので、遅延が悪化します。これは上で書いた通り、格ゲーだと結構クリティカルです。それよりは、NATパンチスルーで簡単にP2P接続できる手段を用意してくれたらありがたかったですね。
というわけで、今回の記事は、「Unityでネットマルチの格ゲー作るならとりあえずUFE2使っとくのが無難じゃないか」という話でした。
今回は格ゲーについてでしたが、今後は他のジャンルについても、ネットコードは闇が深いから下手に自作するより専門家が作ったゲームテンプレート使った方がいいよという話をしていこうかなと思っています。
この記事がなにかの参考になれば幸いです。
[追記 21/07/05]
参考になるリンク
↓格ゲーネットコード、ロールバックに関する詳細な解説記事
Netcode Explaining how fighting games use delay-based and rollback netcode
↓GGPOの作者のトニーさんによるGGPOの解説pdf
https://drive.google.com/file/d/1nRa3cRBQmKj0-SEyrT_1VNOkPOJWNhVI/view
[追記ここまで]