Unreal Engine 4のネットワヌク最適化







少し前、vkの公匏UE4グルヌプで、コミュニティがどのトピックに興味があるかを尋ねたした:)最も人気のあるク゚リの1぀は、゚ンゞン䞊のネットワヌクでの䜜業でした。







初めは、このトピックを䜕らかの圢で明らかにしたり蚀及したりする぀もりはありたせんでしたが、自分やチヌムにずっおも「ベストプラクティス」を蚭蚈するのは良いこずだず思いたした。







ですから、 Armored WarfareAssaultのネットワヌクを䜜成した方法に興味があるなら、catぞようこそ。










゚ンゞンのすべおのバヌゞョンを通過するラむトモチヌフであるUnreal Tournamentから分離されたUnreal Engineを想像するこずはできたせん。 その結果、UE4の匷みの1぀は、基本レベルで゚ンゞンに統合された匷力なネットワヌクツヌルキットです。 私の個人的な評䟡では、同じレベルの質問に぀いお同様に綿密な゚ンゞンはQuake 3゚ンゞンだけです。







高品質のテクノロゞヌの存圚は、開発においお考える必芁性を私たちから奪いたせん。 残念ながら、ネットワヌクの組織に察する無責任な態床が悲惚な結果をもたらした倚くのプロゞェクトを芋おきたした。







この蚘事は決しお「初心者向けガむド」たたは「仕組みの詳现な説明」ではありたせん。 いいえ、これは、ネットワヌクを効果的に最適化できる原理の特定の誇匵されたビュヌです。







仕組み



UE4でマルチプレヌダヌでの䜜業を開始するには、䜿甚可胜な3぀の通信パスを理解する必芁がありたす。









3番目の方法は、クラむアントからサヌバヌにデヌタを報告する唯䞀の方法です。 倉数耇補最初のパスは、サヌバヌずクラむアント間でセクタヌの状態を同期するために䜿甚されたす。 サヌバヌからクラむアントぞのRPCの送信2番目の方法は、特定のデヌタを送信するためのむベントモデルです。







぀たり、このように機胜したす。 耇補された各セクタヌにはNetUpdateFrequencyパラメヌタヌがありたす。このパラメヌタヌは、「ネットワヌク䞊で䜕を亀換するか」に぀いお、セクタヌが1秒間に䜕回ステヌタスをチェックするかを蚭定したす。 デフォルトでは、このパラメヌタヌは非垞識な100.fです。぀たり 、 セクタヌがレプリケヌトされる堎合、デヌタの同期ず送信の詊行はすべおティックになりたす。







結果は明癜で悲しいものです。パケットでネットワヌクを接続するこずは基本的なタスクになりたす。 サヌバヌのCPUの負荷が増加したす。 䞀芋シンプルなプロゞェクトでも同じ粟神で、すべおが遅れ、「䜕も機胜しない」、「キャラクタヌがテレポヌトされる」、「他のプレむダヌが震えおいる」などです。







したがっお、最初のルヌルに到達したす。 耇補されたすべおのセクタヌに適切なNetUpdateFrequencyを蚭定したす。







「適切」ずは、い぀ものように未解決の質問です。 筋金入りの地震のような射手にずっお、キャラクタヌに関係するすべおのもの-圌の動きず歊噚-は、最倧呚波数ず同期されるべきです。 しかし、これは特定のケヌスであり、そのようなプロゞェクトに取り組んでいる堎合、十分な「基本的な」知識ずアプロヌチはありたせん。高品質の補品を入手したい堎合は、さらに掘り䞋げおください。







特定の「平均的な」ケヌス-アヌケヌド、MOBA、モバむル玩具、およびタンクなどの「スロヌシュヌタヌ」では、ネットワヌク曎新の頻床をはるかに䜎くするこずができたす。 AWAssaultでは、戊車のリフレッシュレヌトを1秒間に10回䜿甚したす。 たた、メむンキャラクタヌのネットワヌク曎新の頻床に基づいお動䜜するプロゞェクトを1秒間に6〜8回知っおいたす。







その他のオブゞェクト-さたざたな「キャプチャポむント」、「フラグ」、「カヌトリッゞ」、「ゲヌムの状態」-曎新頻床はさらに䜎くなりたす。 良い䟋デフォルトでは、PlayerState゚ンゞンクラスは1秒間に1回だけ耇補されたす。 セクタの状態の突然の倉曎が可胜な限り迅速に配信される必芁がある堎合、 ForceNetUpdateを呌び出す機䌚が垞にありたす。







セクタヌのコンポヌネントはネットワヌク曎新の頻床を継承するため、1぀のセクタヌを曎新頻床の異なる郚分に「分割」するこずはすぐに思い浮かぶこずに泚意しおください。タスクは簡単ではありたせん。 より正確に蚀えば、䞀郚のコンポヌネントが党䜓ずしお生掻できるセクタヌずは異なる呚波数を必芁ずする堎合、慎重に別の゚ンティティにカットする必芁がありたす。 コンポヌネントが所有者より「遅い」ネットワヌク䞊に存圚できる堎合、所有者はすべおのティックを曎新するわけではありたせん-これは正垞な状態です。







ルヌル2 信頌できるRPCは真剣に正圓化される必芁がありたす 。 私たちの郚眲では、信頌できるすべおのrpc機胜が「眲名」によっおヘッドの発行されるずいうゞョヌクを持っおいたす。 すべおのゞョヌクにはゞョヌクがありたす。







それは高䟡であるこずを心に留めおおく必芁がありたす。 ずおも。 RPC自䜓のオヌバヌヘッドは、考えられる結果ほど倧きくありたせん。 ニトログリセリンのボトルず同様に慎重に取り扱っおください。 特にマルチキャストの堎合。 「テレポヌト」を停止した埌に起こる可胜性のある最悪の事態は、信頌できるバッファなどのオヌバヌフロヌが原因でサヌバヌからクラむアントを切断するこずです。 このようなむベントに基づいお構築されたネットワヌクアヌキテクチャは、pingおよびパケット損倱に察しお過敏になりたす。







簡単な䟋アクションに関する通知をサヌバヌからクラむアントに送信したい堎合。 アルコヌルシミュレヌタヌをオンラむンで䜜成し、キャラクタヌ内の各キャラクタヌが肝臓を再生するずしたす。肝臓は別個のコンポヌネントずしお存圚したす。 すべおのクラむアントは、「治療」の各ステップを画面䞊に矎しく衚瀺するために本圓に必芁ですマルチキャスト、信頌できる。 送信する各ティックはRPC LiverHealedfloat HealedHeathです。 2぀のクラむアントの゚ディタヌでのテスト矎しさ、誰もが幞せです。 そしお今、生掻状況クラむアントが足を螏み入れ、パケット損倱、0.5秒以䞊蓄積したすべおのRPCを送信する必芁があり、患者がサヌバヌから喜んでクラッシュする方法を発芋したす。







明らかに、少なくずもサヌバヌのティックごずにRPCを送信する必芁はありたせん。NetUpdateFrequencyが数倍少ない堎合は、単にキュヌを杭打ちしたす。 これらの倀を蓄積し、送信頻床を枛らす必芁がありたす。 そしお、これが信頌できるデヌタであるかどうかをもう䞀床考えおください。そうである堎合は、倉数を耇補せずに行うこずができ、そうでない堎合は、信頌できないデヌタにしたす。 倚くの堎合、クラむアントがゲヌムの䞖界に関するデヌタに基づいおむベントが発生したかどうかをクラむアント自身が蚈算できるかどうかを怜蚎する䟡倀もありたすキャラクタヌの肝臓の同じ扱いは、クラむアントのダニの健康の倉化です。







抂念的なトラップ



たたは、蚀及する䟡倀のあるいく぀かのこず。









ネットワヌクのトリックずトリック



これらは、ネットワヌクの負荷を最適化するこずず、CPUの負荷を最適化するこずの䞡方を目的ずしおいたす。







グロヌバルな状態



ずころで、3番目のルヌル セクタヌを耇補せずにできる堎合は、それを行いたす 。







AWからの2぀の䟋アサルト。このルヌルを実装したすが、方法は異なりたす。









2番目の䟋では、抂念党䜓を次のように説明できたす。







/** Array of bit masks for minimization of space used for destructible actors states. Replication handled by OnRep_DestructableMasks method */ UPROPERTY(ReplicatedUsing=OnRep_DestructableMasks) TArray<int32> DestructedActorsMasks; /** Handles replication of destructible actors masks */ UFUNCTION() void OnRep_DestructableMasks();
      
      





各int32は、最倧32個のオブゞェクトの状態を゚ンコヌドしたす 。 ステヌゞでは、このようなオブゞェクトを1000個以䞊持぀こずができたす。 最倧1024個のオブゞェクトを゚ンコヌドする堎合、2぀のint32ビットマスクの乗算で凊理できたすが、今のずころ、配列の耇補は残しおおきたす。 珟圚の゜リュヌションでも、ネットワヌクをロヌドせずに機胜したす。 マップのロヌド段階では、ネットワヌクを介した条件付き40 intの送信は倧きなデヌタではなく、戊闘䞭に同時に倚くのオブゞェクトが死ぬこずはありたせん。 ゚ンゞンは、フィヌルドの䞀郚を倉曎するずきに配列の最適な耇補を凊理したす。













このアプロヌチは、静的オブゞェクトがサヌバヌずクラむアントの䞡方で明確なロヌド順序を持぀こずに基づいお機胜したす。 それらは配列にキャッシュでき、倉曎されたオブゞェクトのむンデックスのみを耇補できたす。 たた、バむナリロゞックのみが実装生存/砎棄されおいる堎合でも、远加のフィヌルドたずえば、「健康」ず「浞透」が衚瀺される堎合でも、このアプロヌチは正圓化されたす。 これらは、マップ䞊に倚数䜏んでいる同皮のセクタヌです。







壁から完党に砎壊可胜な䞖界を䜜りたいですか そのような状態を通しお圌らず協力しおください。 ビットマスクの圢のいく぀かのintは数千の砎壊可胜なオブゞェクトをコヌド化するのを可胜にするでしょう 。 このような各セクタヌを個別に耇補する「暙準」パスは、サヌバヌのネットワヌクずCPUの䞡方を簡単に殺したす誰が耇補する必芁があるか、誰に、誰に耇補しないかを確認したす。







デヌタのパッケヌゞ化



䞀般に、䞊蚘のポむントはすでに間接的にこのトピックに觊れおいたした。そこでは、シヌン䞊の䜕千ものオブゞェクトの状態に関する情報をビットマスクの配列にパックしたす。 ただし、耇補されたセクタヌ内のフラグにも同じ手法を適甚する必芁がありたす。







ある段階で、タンクには通垞の耇補された10個以䞊のブヌルフラグがあるずいう結論に達したした。 これらは、「戊車は沈む」、「攟火する」、「タヌゲットがロックされおいる」、「死亡した」などの通垞のゲヌムプレむ状態です。







その結果、コアプログラマヌは、 そのような状態を耇補するためのプロキシクラスを䜜成したした 。 䜿甚方法は次のずおりです。







  RepOwnerFlags .Add(&bEnableLockTarget) .Add(&bCanMove) .Add(&bIsDrowning) .Add(&bInWater) .Build(); RepPublicFlags .Add(&bIsDying, this, "OnRep_IsDying") .Add(&bIsMoving, this, "OnRep_IsMoving") .Add(&bIsTurning, this, "OnRep_IsTurning") .Add(&bIsInFire) .Add(&bIsEngineBurning, this, "OnRep_IsEngineBurning") .Add(&bHasMinimapObservers) .Build();
      
      





RepOwnerFlagsおよびRepPublicFlagsは、uint64のラッパヌのように機胜する耇補されたクラス倉数です 。 倉数自䜓は通垞のものになり、゚ンゞンブヌルの芳点からは耇補できたせん。







  /** Notifies of death */ UFUNCTION() void OnRep_IsDying(); /** Identifies if pawn is in its dying state */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Death) bool bIsDying;
      
      





boolをuint81にパックするこずもお勧めです。 耇補された構造内に耇数ある堎合は1です。







はい、同様の芏則がRPC関数に適甚されたす。 いく぀かのブヌルを送信したす-それらをパックしたす。 int32の代わりにvectorずint8可胜であればにfloatを䜿甚するず、同じ状況になりたす。







ファッティ゚クタヌズ



セクタヌの耇補の開始にかなりの時間がかかる状況を想像するのは簡単です。 たずえば、私たちの堎合の戊車の装甲に関するデヌタ戊車の内郚は、レベルに応じおパラメヌタヌが異なる倚数のピヌスで構成されおいたす。







デヌタの倧きなチャンクが1぀のセクタヌから耇補のために到着するず、ネットワヌクは過負荷であるず芋なされ、他のセクタヌもこの間耇補されたせん 。







この堎合、ネットワヌクの飜和を回避する良い方法は、このデヌタを配列の䞀郚に配眮し、飜和の可胜性をチェックしお、 断片的に耇補するこずです。







 bool AMyActor::ReplicateSubobjects(class UActorChannel **Channel, class FOutBunch **Bunch, FReplicationFlags **RepFlags) { bool WroteSomething = Super::ReplicateSubobjects(Channel, Bunch, RepFlags); auto NetDriver = Channel->Connection->GetDriver(); for (int32 i = 0; i < MyDataArray.Num(); i++) { // Check for saturation if (((Channel->Connection->QueuedBits) + Channel->Connection->SendBuffer.GetNumBits() + Bunch->GetNumBits()) >= 0) { return WroteSomething; } auto DataObject = MyDataArray[i]; if (DataObject != nullptr) { WroteSomething |= Channel->ReplicateSubobject(DataObject, **Bunch, **RepFlags); } } return WroteSomething; }
      
      





MyDataArrayは同じデヌタです。 このアプロヌチは、ネットワヌク䞊でセクタヌを䜜成するずきに、ネットワヌク党䜓の「フリヌズ」を回避したす。







この堎合、すべおのプロパティが耇補される前に、ectorが䜜成、衚瀺、およびアニメヌション化されるこずを怜蚎する䟡倀がありたす。 これらのプロパティがその倖芳ず動䜜を決定する堎合、完党なネットワヌク初期化が終了するたで非衚瀺にするこずをお勧めしたす。







結果ではなく状態



ネットワヌク最適化の芳点からは、蚈算の最終結果ではなく、蚈算を生成する条件を顧客に耇補するのが正しいでしょう。 たずえば、キャラクタヌが「芋る」ポむントに関する情報は、クラむアントで蚈算および平滑化できる回転ず照準に関するすべおの蚈算を匕き起こす可胜性がありたす。







コむンの反察偎には、顧客の最適化がありたす。 クラむアントが考慮しなければならないほど、同じ携垯電話でプレむするこずはより快適になりたす。







量子化ベクトル



ベクタヌを完党な粟床で耇補する必芁はほずんどありたせん。 したがっお、 ベクタヌを耇補するには、このビゞネスに最適化された特別なクラス FVector_NetQuantize、FVector_NetQuantize10、FVector_NetQuantize100、FVector_NetQuantizeNormal を䜿甚する必芁がありたす 。







個人的な慣習からFVector_NetQuantize100を超える粟床は必芁ありたせん。絶察的な倧倚数では、FVector_NetQuantizeずFVector_NetQuantizeNormalがネットワヌクに䜿甚されたす。







ネットワヌク関連性を䜿甚するしない



ゲヌムキャラクタヌのネットワヌク関連性が必芁な理由がわからない堎合は、無効にするこずをお勧めしたす。 ゚ンゞンのデフォルト蚭定は、地震のようなシュヌティングゲヌムUTの耳、すでに述べた向けに蚭蚈されおいたす。 それらは、芖芚的に開かれた䞖界を持぀ゲヌムには適さず、「脂肪」セクタヌの堎合もあたり快適ではありたせん。







ectorずプレヌダヌ間のNetCullDistanceSquared距離の2乗に基づくサヌバヌは、このectorが特定のクラむアントに存圚する必芁があるかどうかを決定したす。 それらの間の距離が倧きい堎合、セクタヌはクラむアントから削陀され、小さい堎合、クラむアント䞊で再䜜成されたす。 この操䜜は、5秒のタむムアりトで実行されたすデフォルト倀はRelevantTimeoutです。







ここでキヌが再䜜成されたす。 fat ectorの堎合、このプロセスは、オブゞェクトのスポヌン時にネットワヌクを詰たらせるか、フリヌズを匕き起こす可胜性がありたすそのリ゜ヌスがメモリからアンロヌドされた堎合。 オヌプンワヌルドの堎合、それは「どこからでもない」堎所の真ん䞭に珟れるこずでもありたす。 あなたのセクタヌが垞に「境界線䞊」で実行されおいる堎合デフォルトでは、キャラクタヌから150メヌトル実行されたす、このプロセスは䞍快な堎合がありたす。







同時に、適切に調敎された関連性は、ゲヌムプレむでこれを行うこずができる堎合、トラフィックず神経を倧幅に節玄できたす 。 AWAの堎合、ネットワヌクの関連性は䞀切䜿甚されたせん。「戊車は怜出された堎合にのみクラむアントに衚瀺される」ずいう通垞のスキヌムずは察照的に、マップ党䜓で敵の戊車を芋るこずができたす。







もちろん、組み蟌みのメカニズムに基づいお関連性を制埡できるだけでなく、 AActor :: IsNetRelevantFor ...を再定矩するこずでも関連性を制埡できたす。 ネットワヌク最適化の考慮事項により、䞍正行為から保護するために、これが必芁になる堎合がありたす。 たずえば、MOBA戊争の霧の䞭に隠されたキャラクタヌは、最も平凡なマップハックを避けるためにクラむアントに耇補されるべきではありたせん。 デヌタなし-キャンディヌなし。







ネットワヌクのデバッグ



プレむテスト



プレむ。 それをテストしたす。 ご芧ください。 線集者や枩宀の条件ではなく、実際の条件で-組み立おられたクラむアントずサヌバヌが戊闘条件で展開されおいたす。 開発マシン䞊のロヌカルサヌバヌは 、特に4000 flopsのパフォヌマンスの仮想マシンを䜿甚する堎合は特に悪い考えです。







そしお、はい、゚ディタヌでのネットワヌクのテストがどれほど䟿利であっおも、特にコン゜ヌルやモバむルデバむスに関しおは、実際のアセンブリはただ別の䞖界です。 䞍完党な状態での顧客の行動は異なりたす。







ネットワヌクプロファむラヌ



゚ンゞンを完備した玠晎らしいナヌティリティ NetworkProfiler







぀い最近、これは特定のタンクの接続解陀の原因を怜玢する方法です。













プロファむラヌには奇劙な機胜があり、モバむルデバむスでの䜿甚は制限されおいたすが、ネットワヌクデヌタの党䜓像を理解するこずができたす 。







これは、疑わしい「脂肪」デヌタずネットワヌクスパむクを識別するのに最も圹立ちたす。 䜿甚する必芁がありたす。







貧匱なネットワヌクシミュレヌション



プレむテストでは、明らかなネットワヌクの問題のみを特定できたす。 残念なこずに、有料ナヌザヌが遠くの村に座っお、Wi-Fiルヌタヌず家に3メヌトルのアンテナがあり、そこからむンタヌネットがこのルヌタヌに行き、3キロ離れた携垯電話の塔から本圓の問題が始たりたす。 pingが十分に適切であるずいう事実にもかかわらず、 この構成ではパケットに䜕が起こる可胜性がありたす 。







UE4は、「箱から出しおすぐに」、pingの埅ち時間、パケット損倱、誀った順序など、さたざたなネットワヌク状態をシミュレヌトできたす。 詳现に぀いおは、こちらをご芧ください ネットワヌクベヌスの゚クスプロむトを芋぀ける







叙事詩蚘事の䟋では、iniでパラメヌタヌを指定しおネットワヌクを構成しおいたすが、テストではこれはあたり䟿利ではありたせん。 さらに、完党なテストを行うには、゚ディタヌを再起動せずに、実行時に耇数のプリセットを甚意しおそれらを切り替えるほうが䟿利です。







これは次のように行われたす。UE4/ Engine / Binaries /フォルダヌで、このコンテンツを䜿甚しお、network_bad.txtなどのファむルを䜜成したす







 Net PktLoss=1 Net PktOrder=0 Net PktDup=0 Net PktLag=120 Net PktLagVariance=0 p.netshowcorrections 1
      
      





これで、゚ディタのコン゜ヌルでexec network_bad.txtを盎接呌び出しお、説明されおいる蚭定を適甚できたす。 既に理解したように、これは単なるファむルに「パック」されたコン゜ヌルコマンドのセットです。







亀通監芖



専甚に䞊げたす。 プレむテストを準備したす。 単䞀のポヌトでトラフィックを監芖したす。 入堎ず退堎の平均トラフィック量を芋積もりたす。







この点は非垞に明癜ですが、䜕らかの理由で倚くの人がそれを無芖しおいたす。







あずがき



anrialでマルチプレヌダヌで䜜業するずきに、䞀般的なレベルで基本的に重芁だず思うすべおのこずに぀いお簡単に話そうずしたした。 遅延補正、ネットワヌク補間/倖挿、ネットワヌクアヌキテクチャの機胜に぀いおは無限に語るこずができたすが、これらはすべお䞊蚘ず同じ原理ずアプロヌチに基づいおいたす。 はい、別の蚘事に倀したす。







AWAssaultでの結果-問題や重倧な遅延なしに3Gネットワ​​ヌクでプレむする胜力。 安定した接続ではあるがEdgeでも十分ず蚀えたす。 私の意芋では、これらは16人のプレヌダヌのマルチプレヌダヌにずっお非垞にたずもな数字です。 チャンネルの厚さに加えお、他の倚くのゲヌムずは異なり、pingに察しおも重芁ではありたせん。







補足、反論、議論するこずがあれば、コメントを歓迎したす :)








All Articles