UDN
Search public documentation:

NetworkingOverviewJP
English Translation
中国翻译
한국어

Interested in the Unreal Engine?
Visit the Unreal Technology site.

Looking for jobs and company info?
Check out the Epic games site.

Questions about support via UDN?
Contact the UDN Staff

Unreal ネットワーク アーキテクチャ

ドキュメントの概要:Unreal ネットワーク アーキテクチャの概要。 Tim Sweeney により作成。

ドキュメントの変更ログ: Steve Polge によりポート化および更新。 Richard Nalezynski? により更新および管理。

概要

マルチプレイヤ ゲームで最も大切なこと。 それはリアリティーの共有です。つまり、各プレイヤが、自分達は同じワールドに共存し、そこで繰り広げられる出来事をそれぞれの視点から見ているというリアリティーを感じられるということです。 マルチプレイヤ ゲームは、Doom のような 2 プレイヤ用の小型モデムに始まり、 Quake 2Unreal 、そして Ultima Online といった、大きくて継続性があり、フリーな対話も実現したものへと変遷し、そのリアリティー共有を支えるテクノロジーは驚くべき進歩を遂げました。

ネットワーキングをゼロから実装する

1 つ気づいていただきたい重要な点は、ゲーム内にネットワークされたマルチプレイやをサポートする予定がある場合には、まず最初にビルドインして、ゲームを開発するのと同じようにテストしてください ! 効果的なネットワークの実装のビルドは、ゲームオブジェクトのデザイン決定に重大な影響を与えます。 ソリューションの改良は難しく、手間が大変かかります。 ソリューションを後から組み込むことは難しく、ネットワーキング (多数のオブジェクト上への機能分配など) を考慮に入れる前は理にかなっていた設計上の決定事項が、マルチプレーヤーゲームで深刻な問題を引き起こす可能性があります。

ピアツーピア形式

最初に登場したのは、 DoomDuke Nukem.といったピアツーピア形式のゲームでした。ゲーム中はどの端末も同等であることがこれらのゲームの特徴です。両機で入力内容とそのタイミングが完全にシンクロし、全く同じ入力により全く同じゲームロジックが実行される、というものでした。完全なる確定的ゲームロジック(例えば定率、非ランダムなど)であったため、マシンでプレイヤが体験するリアリティーは同じものでした。

この種のゲームの長所は単純性でした。一方の短所は次の通りです。

  • 継続性がない プレイヤ全員が同時にゲーム開始しなければならず、追加プレイヤの参加ややめたい人が途中で抜けることは出来ませんでした。
  • プレイヤの拡張性がない ネットワークが横並び構造をとっているため、連動負荷やネットワーク誘発エラーがプレイヤ数に比例して増加してしまいます。
  • フレームレート拡張性の欠如 プレイヤ全員が同じ内部フレームレートで実行する必要があったため、非常に多様なマシンスピードに対応するのは困難でした。

クライアント サーバー形式

さて、続いて登場したのは単体クライアント サーバー アーキテクチャですが、これは Quake で初開発され、続いて Ultima Online で採用されました。この構造では、一台のマシンを「サーバー」に設定して、ゲームプレーのあらゆる意思決定をここで行っていました。その他のマシンは「クライアント」とし、ここでのキー入力がサーバーに送られ、その結果レンダリングするオブジェクトリストを受信する、という単なるレンダリング端末でした。この技術によって、インターネット上いたる所でゲームサーバーが起動される、大規模なインターネット ゲーム環境が実現されました。後に、使用帯域幅を低く抑えつつ画像詳細度を上げるため、クライアントサーバー アーキテクチャは、シミュレーションと予測ロジックをクライアント側に移行した QuakeWorldQuake 2 へと拡張されました。この構造では、クライアントはレンダリングするオブジェクトのリストに限らず軌道情報をも受信するため、クライアント側でオブジェクトの動きをある程度予測することが出来ました。さらに、気になるクライアント動作のズレを解消すべく、横並び式の予測プロトコルが開発されました。

しかし、この手法にもいくつかの欠点がありました。

  • 非制限無期限でない ユーザーやライセンシーが新種のオブジェクト(武器、プレイヤ コントロールなど)を作成した場合、こうした新規オブジェクトのシミュレーションや予測といった点を定義するため、グルーロジックを加えなければなりません。
予測モデルが難しい:このモデルではネットワークコードとゲームコードが別々のモジュールですが、ゲーム状況がうまく同期し続けるためには、両モジュールが互いに他方の実行内容を完全に把握している必要があります。(完全に)別々のモジュール同士を強く結合させることは、拡張性の低下につながるため望ましくありません。

Unreal ネットワーク アーキテクチャ

そこで、Unreal は、マルチプレイヤ ゲームに汎用クライアントサーバー モデルという新しい手法を採用しました。このモデルでも、ゲームのステートを司る役目はやはりサーバーにあります。しかし実際には、クライアントが自機のゲーム状況の一部を受け持って常に正確に保ち、サーバーとほぼ同じデータに基づいたサーバー同様のコード実行により予測を行います。 これにより、二機間で交換しなければならないデータ量は最小化されます。 サーバーは、複製される関連アクタとその複製されたプロパティにより、クライアントにワールドの情報を送信します。 クライアントとサーバーはまた、関数が呼ばれるアクタを有するサーバーとクライアント間でのみ複製された関数を通して通信しあいます。

さらに、 ゲーム状況 は、拡張オブジェクト指向スクリプト言語によってクライアント独自で記述されており、ゲームロジックはネットワークコードから完全に切り離されます。この言語による記述が可能ならどんなゲームでも統合可能となるため、ネットワークコードは汎用化されます。これにより、拡張性を高めるオブジェクト指向のねらい、つまり、あるオブジェクトの内部実行はハードウェアに組み込まれた他種コードで記述しない、オブジェクトの挙動は完全にそのオブジェクトで記述する、といったコンセプトが達成されます。

基本コンセプト

ねらい


ここでは Unreal のネットワーク構成を非常に厳密に解説します。 複雑な内容がかなりあるため、誤解を招かないために厳密に説明します。

基本用語


以下に基本用語を詳しくご紹介します。

  • variable とは、ひとつの固定名と修正可能な値の関連性をいいます。変数に関連付けられる値の例としては、「X=123」のような整数、「Y=3.14」のような浮動小数点数、「Team=”Rangers”」のような文字列、そして「V=(1.5,2.5,-0.5」といったベクトル、などがあります。
  • オブジェクト とは、ある固定の変数セットからなる内蔵データ構造です。
  • アクタ とは、レベル内を単独で動き回り、レベル内の他のアクタと相互に作用することのできるオブジェクトです。
  • レベル とは、ある一連のアクタを含むオブジェクトです。
  • Tick(ティック) とは、DeltaTime という不定長の時間が経過に伴い実行される、ゲーム状況全てを更新するオペレーションです。
  • ゲーム 状況 とは、ティック実行中でないある時点における、あるレベル内に存在する全アクタ一式、およびその変数の現在の値のことです。
  • クライアント とは、ワールドで発生するイベントの大まかなシミュレーションに適した、ゲーム状況の近似サブセットを維持する Unreal.exe の実行中インスタンスです。
  • サーバー は、単一レベルのチック処理を統括し、ゲーム 状況を間違いなく全クライアントに伝達する Unreal.exe の実行中インスタンスです。

更新ループ


上記コンセプトは、チックとゲーム状況での例外の可能性を除けば、いずれも汎用的です。そこで、これらについてより詳細にご説明します。はじめに、Unreal の更新ループについて簡単にご説明しましょう。

  • サーバー ならば、全クライアントとカレント ゲーム状況を交信する。
  • クライアント ならば、要求動作をサーバーへ送り、新規ゲーム 状況情報をサーバーから受信し、画面に現在のワールドの概観をレンダリングする。
  • 前回の Tick(ティック) から、任意の時間 DeltaTime (デルタタイム) が経過したら、 Tick(ティック)処理 によりゲーム状況を更新する。

Tick(ティック)処理の内容は、レベル内の全アクタの更新とそれらの物理演算の実行、発生したゲームイベントのアクタへの通知、およびスクリプトコードの実行などです。Unreal の物理や更新コードはすべて、可変量の経過時間に対処できるように設計されています。

例えば、Unreal の運動物理は以下のとおりです。

   Position += Velocity * DeltaTime
  

これにより、フレームレートの高い拡張性が実現されます。

Tick(ティック)処理の間、ゲーム状況は実行コードにより常に修正されます。次の 3 つのケースにおいて、ゲーム状況は変更されます。

  • アクタ変数が修正された場合
  • アクタが作成された場合
  • アクタが破壊された場合

サーバーこそ真


上記から、サーバーのゲーム状況は、あるレベル内の全アクタの変数すべてによって完全かつ簡潔に定義されています。サーバーはゲームプレー フローの権威であり、サーバーのゲーム状況が常に真のゲーム状況とみなされます。クライアントマシンのゲーム状況 バージョンは常に、サーバーのゲーム状況から逸脱した多様な近似ステートであると考えます。クライアントマシンに存在するアクタはプロキシと捉えられますが、これはアクタがオブジェクトそのものではなくオブジェクトの暫定的な近似描写であるためです。

ネットワークされたマルチプレイヤゲームで使用するため、クライアントがレベルをロード時、 TRUE に設定されている bNoDelete または TRUE に設定されている bStatic を持つアクタを除き、レベルにあるアクタすべてが削除されます。 クライアント(サーバーにより決定される)に関連する他のアクタは、サーバーからクライアントに複製されます。 複数のアクタは( GameInfo アクタなど)は、決してサーバーに複製されません。

帯域幅の制限


ネットワーク帯域幅が無制限だったなら、ネットワークコードはいとも簡単なものとなります。例えば、サーバーは各チック終了時に、各クライアントに向けてゲーム状況のありのまま全てを送信するだけでよいからです。 そうすれば、クライアント側では常にサーバーで進行するゲーム通りのビューがレンダリングされます。しかしながら、実際のインターネットでは、28.8K モデムの場合、正確な更新情報すべての交換に必要とされる容量の 1% 程度でしかありません。ユーザーのインターネット接続環境は今後も益々早くなって行きますが、帯域幅の改良スピードは、ゲームやグラフィックの進歩度を示す「Moore の法則」をはるかに下回っているのです。つまり、ゲーム状況アップデートを完全にカバーできる帯域幅が得られる日が来ることはないでしょう。

さて、ネットワークコードの主たる目的は、サーバーからクライアントへの、適度に近似したゲーム状況の配信です。 これにより、帯域幅の制限を守りつつリアリティーが共有できる程度にインタラクティブなワールドのビューのレンダリングが、クライアント側で実現されます。

複製


Unreal では「サーバー・クライアント間のリアリティー共有に適した近似調整」という一般的問題を「複製」の問題とみなします。つまり、近似リアリティー共有を実現するためにサーバー・クライアント間で行われる、一連のデータおよびコマンドの定義に関する問題です。

アクタ

役割

通常、すべてのはアクタは RoleRemoteRole プロパティを持ちます。それらは、サーバーとクライアントで異なる値を持ちます。 サーバーのすべてのアクタは、 ROLE_Authority に設定する Role を持ちます。

サーバーのすべてのアクタは、 RemoteRole を持つ可能性があります。

  • ROLE_AutonomousProxy (所有するクライアントを複製時、PlayerControllers と Pawn を操作)
  • ROLE_SimulatedProxy (他の複製されたすべてのアクタ)
  • ROLE_None (クライアントに複製されたことがないアクタ)

サーバー上のアクタの RemoteRole は、クライアント上にあるアクタの Role です。 すべてのアクタは、 ROLE_Authority に設定される RemoteRole を持つクライアントに複製されます。

定義 Actor (アクタ) クラスは ENetRole エミュレーションと RoleRemoteRole の 2 つの変数を以下の様に定義します。:

  // ネット変数
  enum ENetRole
  {
  ROLE_None,              // 役割なし
  ROLE_SimulatedProxy,   // このアクタのプロキシをローカルでシミュレーションする
  ROLE_AutonomousProxy,   // このアクタのプロキシはローカルで自立する
  ROLE_Authority,         // アクタのコントロール権限
  };
  var ENetRole RemoteRole, Role;
  

RoleRemoteRole といった変数はローカルおよびリモートのマシンをどの程度コントロールするのかが個々にアクタについて記述されています。

  • Role==ROLE_SimulatedProxy は、アクタが物理とアニメーションをシミュレーションする一時的近似プロキシであることを意味します。クライアント側で、シミュレーションされたプロキシが基本物理(直線や重力関連の動きや衝突)を実行しますが、高度な動きの決定はせずにそのまま進みます。 それらは、 simulated キーワードを持つスクリプト関数のみを実行することができ、 simulated とマークされた状態のみを入力できます。
これはネットワーク クライアントでのみ生じる状況で、ネットワーク サーバーや単一プレイヤのゲームでは起り得ません。
  • Role==ROLE_AutonomousProxy はアクタがローカルプレイヤであることを意味します。自立プロキシには、クライアント側で動作を(シミュレーションというよりも)予測するために組み込まれた特別なロジックがあります。 クライアントであらゆるスクリプト関数を実行することができ、あらゆる状態を入力することもできます。
これはネットワーク クライアントでのみ生じる状況で、ネットワーク サーバーや単一プレイヤのゲームでは起り得ません。
  • Role==ROLE_Authority は、アクタのコントロールに関し絶対的権限を有するということです。
これは単一プレイヤのゲームにおける全てのアクタにあてはまります。 クライアントであらゆるスクリプト関数を実行することができ、あらゆる状態を入力することもできます。

これはまた、サーバー上の全てのアクタにもあてはまります。 クライアント上では、使用帯域幅を減らすためにクライアント側でなされた特別な措置といった、ローカルでクライアントによって Spwan(スポーン) されたアクタにあてはまります。 サーバー側では、全てのアクタに Role==ROLE_Authority があり、 RemoteRole はあるプロキシタイプに設定されます。クライアント側では、 RoleRemoteRole はサーバーの設定値と比較して、常にその反対に設定されます。これは RoleRemoteRole の意味合いからして当然のことです。

ENetRole の値のほとんどは、 ActorPlayerPawn といった UnrealScript のクラスにおける複製命令文で定義されます。複製命令文で様々な役割値の意味を定義する例を挙げてみます。

  • Actor クラスにある複製定義により、 Actor.AmbientSound (アクタ.アンビエントサウンド) 変数は、サーバーからクライアントへ送信されます。: if(Role==ROLE_Authority) AmbientSound;
  • アクタクラスの複製定義により、 Actor.AnimSequence (アクタ.アニメーション シーケンス) 変数は、サーバーからクライアントへ送信されますが、これは、メッシュとしてレンダリングされたアクタのみだけです。: if( DrawType==DT_Mesh && (RemoteRole<=ROLE_SimulatedProxy) ) AnimSequence;
  • PlayerPawn クラスにある複製定義のため、クライアントは、 FireAltFire 関数のサーバーへの呼び出しを複製します。: if( Role<ROLE_Authority ) Fire, AltFire;
  • Actor クラスにある複製定義により、シュミレーションされたプロキシの Velocity が初めてスポーンされた時、サーバーはクライアントにそれと移動ブラシを送信します。 if( (RemoteRole==ROLE_SimulatedProxy && (bNetInitial || bSimulatedPawn)) || bIsMover ) Velocity;

すべての UnrealScript のクラスにある複製命令文を学習することにより、全ての役割の内部処理が理解できるようになります。複製に関する、非常に小さな「舞台裏のマジック」があるのです。低級の C++ では、アクタ、関数呼出し、そして変数の複製に関する基本構造をエンジンが供給します。高級の UnrealScript では、様々な役割に基づいてどの変数や関数が複製されるべきかを支持することにより、様々なネットワークの役割の意味が定義されています。ですから、役割の意味が UnrealScript 自身で定義されたものなのです。 ただし、物理やアニメーションをシミュレーション プロキシ用に条件付で更新する、C++ の舞台裏ロジックは別です。

関連性

定義


Unreal のレベルは巨大になることが多く、プレイヤに見えるレベル内アクタは、どんな時もほんの一部だけです。その他のレベル内アクタのほとんどは不可視で、オーディオも無効で、プレイヤに影響する効果も全くありません。サーバーが可視もしくはクライアントへの効果有効と判断した一連のアクタは、そのクライアントにとってのアクタの関連セットとみなされます。Unreal のネットワークコードにおける帯域幅最適化機能では、サーバーがクライアントにクライアントの関連セットにあるアクタのみを通知します。

Unreal では以下のルールを (順番に) 適用して、プレーヤーに関連するアクタのセットを決定します。

  • アクタの RemoteRole が ROLE_Noen の場合、関連性はありません。
  • アクタが別のアクタの骨組みにアタッチされている場合、そのベースの関連性によって関連性が決定されます。
  • アクタの bAlwaysRelevant が設定されている場合、関連性があります。
  • アクタに bOnlyRelevantToOwner=true が設定されている場合 (Inventory に使用)、唯一の可能性としてそのアクタのオーナープレーヤーのクライアントと関連性があります。

  • アクタが static=true (固定=有効) または bNoDelete=true (非削除=有効) の場合、関連している。
  • アクタが ZoneInfo (ゾーン情報) クラスの場合、関連している。
  • アクタがプレイヤ( Owner==Player )に所有されいる場合、関連している。
  • アクタが Weapon (武器) で、可視アクタにより所有されている場合、関連している。
  • アクタが、非表示 ( bHidden=true (非表示=有効))、衝突なし( bBlockPlayers=false (プレイヤをブロック=無効))、そしてアンビエントサウンドがない( AmbientSound==None (環境音==なし))の場合、アクタは、関連していない。
  • アクタが、アクタの Location (場所) とプレイヤの Location の間での視線チェックにより可視の場合、関連している。
  • アクタが 2~10 秒以内前(正確な秒数は行われるパフォーマンス最適化によって異なる)に可視だった場合、関連アクタである。

これらのテストは、仮想関数 AActor::IsNetRelevantFor() で実装されています。 bStaticbNoDelete のアクタ (クライアントに滞在する) も複製されることに注意してください。

以上のルールは、プレイヤに必ず影響を与えるアクタセットを適度に近似するよう設定されたものです。もちろん、これで完全ではありません。例えば、大きなアクタの視線チェックには時折偽陰性がみられますし(これには経験則で対処されますが)、環境音の閉塞状態も確認しない、といったことです。とはいえ、近似でのエラーは、インターネットというかなりの待ち時間が必要でパケット損失が常である、ネットワーク環境につきもののエラーによって引き起こされているのです。

Repnotify キーワードでマークされたプロパティが複製されると、UnrealScript の ReplicatedEvent() イベントが呼び出され、変更されたプロパティの名前をパラメータとして渡します。ネットワーク帯域幅の節約にこれをどのように利用できるかについては、「複製のパターン」セクションを参照してください。

クラスごとに NetPriority (ネット プライオリティ) のデフォルト設定をうまく調整します。発射物やプレイヤには極めて高いプライオリティを、単なる装飾効果には低いプライオリティをあてます。Unreal で設定されているデフォルトは、当初の見込み適正値ですが、必要に応じて調整して状況改善して下さい。 アクタがクライアントに初めて複製されると、変数は全て各クラスのデフォルト値に初期化されます。続いて、最終値と異なる変数のみが複製されます。つまり、なるべく多くの変数が自動的にクラスのデフォルトに設定されるよう、クラスを自分で設計すると便利です。 例えば、アクタは LightBrightness 値、123 を常に持つようにする場合には 2 つの方法があります。 (1) LightBrightness のデフォルト値を 123 に設定するか、 (2) アクタの BeginPlay 関数で、initialize LightBrightness を 123 に初期化します。 LightBrightness 値は複製がまったく必要でないため、 最初の方法のほうが効率的です。2 つ目の方法は、アクタが最初にクライアントに関連づけられるたびに LightBrightness の複製が必要です。

また、次の状況にも気をつけてください:

  • アクタ参照をシリアライズできない場合、=bNetInitial= と bNetDirty はクリアされません (その参照はクライアントとの関連性がないため)。つまり、サーバーはこのプロパティの複製を続けることになり、CPU サイクルのコストが上がります。この問題の回避例として、Native の複製コード (Base、Controller および Instigator の複製) を参照してください。
  • 配列の複製はやめてください。配列メンバの値が 1 つでも変わると配列全体が複製されるからです。
  • プロパティ (ベクトルと回転) は、複製のため切り詰められます。

Native (C++)


サーバーの CPU 使用の最適化には、Native の複製関数を使用します。
  • クラス定義用の NativeReplication キーワード
  • AActor::GetOptimizedRepList() のクラスバージョンを実装する。
  • 各複製プロパティの RepIndex を生成するため、スクリプト Replication{} 定義が必要。
  • 場合によって意は、APickupFactory バージョンのような、 GetOptimizedRepList() を大量に最適化できます。
  • AActor::IsNetRelevantFor()
    • Pawn (1 つのクライアントのみの単一パス時、 Pawn の関連性に基づき、Weapon Attachment(武器添付)のようなものが関連しているため) の総関連キャッシング: bCachedRelevant flag.

不正行為検出と防止


弊社では、 Unreal Tournament にて次のタイプのネットワーク関連の不正行為に直面しています。:
  • Speedhack
    • 動作更新にクライアントクロックを使用している事実の利用
    • クライアントと過度に異なる率で進まないサーバーを確認することによる、Built-in 検出。
    • 大幅なパケット損失を伴った偽陽性
  • Aimbots - UnrealScript と社外バージョン
  • Wall hack と Radar - UnrealScript と社外バージョン

トラフィックの監視


ネットワーク トラフィックを監視するため、ライセンシーは以下の記述とエンジンをコンパイルすることができます。


サーバーの CPU 使用の最適化には、Native の複製関数を使用します。

これは、 DevNetTraffic ( Debug で自動) を通してネットワークの統計地集計を有効化します。 ネットワークの統計地を非抑制にするには、ゲームエンジン構成で Suppress[#]=DevNetTraffic をコメントアウトします。

DevNetTraffic がある場合は、ネットワークデータ全体の要約データがログに書かれているマシンで受け取ります。 要するに、サーバーにより送信されたデータを見るには、クライアント側でこれを行ってください。 クライアントにより送信されたデータを見るには、サーバー側でこれを行ってください。ログに書かれたデータは非常に冗長な形式で、全てのパケットにタイムスタンプがあり、全ての複製アクタ、変数そして関数呼出しに要約がついています。

下記のコンソールコマンドは、非抑制的なネットワーク統計地集計に使用されます。

  unsuppress DevNetTraffic
  

ネットワークドライバの実装

プラグイン形式ネットワークドライバ


Unreal の提供するネットワーク環境は、C++ の UNetDriver (Uネットドライバ) クラスに基づく、プラグイン式インターフェースが採用されています。Unreal Engine では UNetDriver (Uネットドライバ) クラスを通してあらゆるネットワーク問題を処理します。 そして、Unreal.ini ファイルにデフォルトは以下のように定義されている最適なネットワークドライバを、同時に読み込みます。

  [Engine.Engine]
  NetworkDevice=IpDrv.TcpNetDriver
  

Unreal のサポートする最新インターネット環境は、 TcpNetDriver という名の UDP ネットワークドライバです。しかし、 UNetDriver の新規サブクラスを作成し、 TcpNetDriver のソースを、新規関数を実装する際の参考にして、新種のネットワーク環境を作ることも可能です。実際、Maverick Software のチームが、このインターフェースを利用して Unreal の Mac 版用に AppleTalk ドライバを作成した例があります。

ネットワークドライバは、接続開始、接続終了、データ送信、そして不確実なデータの受信を行います。しかし、データのコンテンツは Unreal Wire Protocol (Unreal ワイヤープロトコル) で定義されており、ネットワークドライバ側では全く感知しません。つまり、 UNetDriver h では交信中の情報内容が全く把握されておらず、ただ送る、受け取る、を行っています。特徴は以下のようになります。

コネクション方式 UNetDriverUNetConnection サブクラスの定義する一連の接続を維持します。 UNetDriver は、コネクションレス プロトコル(UDP など)階層の初めにあり、接続保守、タイムアウト管理などのための独自の内部ロジックが必ず含まれます。 UNetDriver は、ストリーム方式ではなく、パケット方式です。全てのデータは 0...MAX_PACKET_SIZE (最大パケットサイズ) の大きさの個別パケットにある UNetDriver を通じて送受信されます。

パケットは不確実に送信されます。パケットの確実な送受信は全て、=UNetDriver= には非可視なハイレベルで処理されます。あるマシンから別のマシンへと送られたパケットは到達したりしなかったり、また複数回到達したり、ということもあります。更に、到達したパケットの処理不良や大幅な遅延の可能性もあります。

パケット自体は決して損傷しません。パケットが受信されたら、そのサイズとコンテンツは送り側のそれと同じものが保証されます。

インターネットドライバ


Unreal のインターネットは、不確実なコネクションレスの通信に標準インターネット プロトコルである UDP をベースにしています。Unreal のクライアント サーバー間のゲームプレイは全て、UDP アドレス(クライアントとサーバーがそれぞれ 32 ビットインターネットアドレス、16 ビットポート番号を持つ)の一定かつ不変な組み合わせによって調整されます。 デフォルトのポート番号は Unreal.ini 構成ファイルにあります。

つまり、Unreal の UDP パケットは非常にプロキシが容易で、プロキシでの内容把握がないまま、ユーザーが意識することなくプロキシ可能です。

Unreal ワイヤー プロトコル

Unreal のワイヤー プロトコルではパケットのコンテンツをビットストリームで定義します。プロトコルでは、変数や関数の複製、アクタ作成、アクタ破壊、ファイル転送、そしてパケットの信頼性の高低の交換(種々の環境で両タイプが使われる)といった、様々なテーマについて処理します。

このプロトコルは効率性と信頼性を改善するために何度も大幅に変更されていますが、今後パケットフォーマットを文書化する予定はありません。

言い忘れてはならないのが、このプロトコルは Unreal パッケージ ファイルのフォーマットのデータ構造 (Unreal パッケージ ドキュメントで説明しています) と密接な関係があるため、外部アプリケーションがこれを解析して何かに役立てるのは非常に難しいであろうということです。ソースコードとコメントを読むのが一番役に立つでしょう。

Unreal の今、そして、これから

Unreal のネットワーク アーキテクチャを語るとき、「強力」、「総合的」、「複雑」、そして「習得が困難」といった表現がよく使われます。そして今、力強さや単純性、そして特定の問題の解決のための実用的ニーズなど、現在のソリューションが実現されるべく、ゲーム開発の中でアーキテクチャは非常に顕著な進化を遂げました。

プログラミングの簡便性という視点で考えた理想的なネットワーク アーキテクチャは、クライアントがまさに単なるレンダリング端末であるかのように振舞うクライアントサーバー モデルです。しかし、以前にもお話したとおり、回線容量の進歩とハードウェアの進歩の比率を分析してみると、単なるクライアントサーバー モデルでは予測可能な未来など非現実的となってしまう状況にあることが分かります。

つまり、クライアント側での豊かな物理シミュレーション力と、スクリプト実行のほとんどが次世代ネットワークエンジンに匹敵します。Unreal では、汎用ネットワークモデルはオブジェクト、オブジェクト変数、そしてオブジェクト関数呼出しの汎用複製に基づいて定義されています。このモデルは、いかなる特定のシミュレーションモデルに決め打ちすることもなく、豊かなシミュレーション性能を提供します。

Unreal の広範なネットワーク アーキテクチャこそ、最高のものだと強く確信しています。現在の方向を確定する一方で調査した分野には、データベース複製、UnixRPC、CORBA 分散オブジェクト モデル、そして JAVA RPC があります。一般的結論は、優れたアイデアがいくつもありますが、インターネット技術やゲーム開発者にある制限に圧力をかけるようなものは何もない、ということです。Real-time 3D (リアルタイム 3D) のようなその他の調査分野でも、全く同じことが言えると思います。

今後このモデルが拡張と進歩を遂げるであろう分野が沢山あります。マルチキャスト複製関数を追加すると、可変複製せずに処理可能なシミュレーション量を増やせます。ピア プロキシモデルの拡張により、サーバー間で NPC オブジェクトの現実的リアルタイム フローを可能にするサーバーのバックボーンが生成されます。複製オブジェクトモデルは、ユーザーインターフェースやチャットシステムといったエンジンの他分野に拡張される場合もあります。分散したユーザー修正可能なシステムの性質を維持しつつも、 _Ultima Online のワールドなどのより豊かで持続性のあるゲーム環境にこのアーキテクチャが適用される可能性が濃厚となっています。数年内に、ネットワーク機能はゲーム開発の極めて注目される分野となることでしょう。

-Tim Sweeney