UDN
Search public documentation:

GameStateReplicationJP
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

UE3 ホーム > ネットワーク & レプリケーション > ゲーム状態の複製

ゲーム状態の複製


概観


特定のクライアントと関連のあるそれぞれのアクタについては、サーバーは該当するアクタおよびクライントに対して、一連の複製チェックを実行します。これらのチェックにより、どの変数をクライアントに対して複製するか、ならびに (ローカルマシンで実行する代わりに) 特定の関数をクライアントに送信して実行させるべきかどうかを決定します。同様に、クライアントは (変数ではなく) 関数をサーバーに対して複製することができます。このように、アクタに関するデータを送信するプロセスを「複製」と呼びます。ただし、変更したデータの送信同様、アクタに関するあらゆるデータを送信すると接続がオーバーフローしてしまいます。そのため Unreal では、特定のクライアントが必要としているデータのみを複製するアプローチを採用しています。

複製チェック


サーバーにおけるクライアント数、各クライアントに関連したアクタの数、あるいは各アクタの変数に対する複製チェックの回数などを考慮に入れると、ネットワーク上にどのデータを送信するか特定する作業において、大量のチェックが実行されることになります。そのため、複製処理文を導入する際には細心の注意を払い、送信対象を算出するプロセスにおいて CPU の負荷を高めないようにしてください。複製処理文の関数呼び出しには長時間かかるため、複製処理文において関数を呼び出すことは避けてください。必要に応じて、Tick において関数の結果を算出し、複製処理文の関数値を使用します。また、必要な場合にのみ状態を評価するなど、チェックは可能な限り簡潔に行ってください。最後に Epic では、アクタ、インベントリ、そして他の一般的なクラスにおける関数の複製状態を評価するプロセスには、長時間かかることを把握しています。サーバー CPU の負荷を軽減するため、Epic はこれらの変数のチェックをネイティブ コードに移動させました。そのため、いくつかのエンジン クラスにおいて、 nativereplication と表示されます。複製用に評価された変数はすべて、通常は UnActor.cpp にあるネイティブ複製コードよって処理されます。しかし、UnrealScript 複製処理文もまた、チートの防止やソースのない作成者/編集者用のドキュメント化などの面で重要です。nativereplication クラスで定義されていない変数(nativereplication 以外のサブクラスまたはスーパークラスで定義されているもの) はすべて、unrealscript 定義を介して複製されます。

高信頼性 vs 低信頼性


ネットワークにおいて使用されているもう 1 つの最適化プロセスとして、高信頼性データと低信頼性データの差が挙げられます。変数の場合、データはすべて信頼できます。変数がクライアントに到達しなかった場合、これは必ず再送信され、最終的には目的の宛て先に到達します。順序が適切でないパケットを許可する際には、最新の状態を維持するため、もっとも高い番号が付けられたパケットの変数データが使用されます。ただし、関数は高信頼性または低信頼性の両方の状態で存在します。高信頼性の関数は、他の信頼できる関数と相対的に、送信されたものと同じ順序でクライアントに確実に到達します。しかしながら、低信頼性の関数はクライアントには送信されますが、必ず受信される保証はありません。

複製データの近似化


もう 1 つの最適化方法として、Unreal がどのようにしてベクター、ロテータ、アレイをインターネット上に送信するかが挙げられます。これらの規則は、関数の引数と変数の双方に適用されます。

  • Vectors: 各コンポーネントが、もっとも近い整数に切り上げられます。
  • Planes: 各コンポーネントが、もっとも近い整数に切り上げられます。
  • Rotators: 各コンポーネントに対して、255 の特有の値を割り当てることができます。次に、値は接続先において、0 ~ 255 から 0 ~ 65536 までスケール アップされます。 Structs: 全部またはゼロ。いずれかのエレメントが変化すると、struct 全体が複製されます。
  • Static Arrays: アレイ内で変更したエレメントのみを送信します。動的アレイは複製できません。
  • Strings, Structs: 448 バイトよりも低くしないと、この変数が原因で、該当するアクタの残りの変数が足りなくなってしまいます。
  • CompressedPosition: ベクターおよびロテータに対して上記の変換 (常にゼロである Rotator.Roll を除く) が適用されます。速度コンポーネントには、ベクターと同じ変換が適用されます。

複製処理文の規則


独自の複製処理文を書き込む際には、知っておくと便利なことがいくつかあります。まず、複製処理文の定義は、変数が定義されたクラスでのみ可能です。そのため、複製処理文をオーバーライドすることはできず、また、複製処理文の定義は、データを定義している適切なクラスで行う必要があります。変数の複製状態のオーバーライドが必要な状況にある場合、おそらくアクタに対して誤ったロールを使用しています。このデータを複製するため、どのようなタイプのロールを持たせるかについて再検討してください。これにより、アクタクラスに変数 DrawType が含まれる場合、その複製状況はどこで確認できるかがわかります 。これはアクタクラスにしか存在しません。それでもデータの複製が必要な場合は、キャリアメッセージとして機能する新規アクタを作成し、これを接続先の真の変数に対してコピーする方が多くの場合において簡単です。

UE3 までは、複製関数は複製変数と同じ方法で宣言されていました。UE3 では、これが変化しました。複製関数の定義は、現在では関数変更子( serverclientreliableunrealiable ) でのみ行われます。これらの変更子の意味合いは、いたって単純です。関数が宣言された server がサーバーで実行されるほか、通常はクライアントによって呼び出されます。関数が宣言された client が、アクタが所有するクライアントで実行されます。 clientserver は、 reliableunreliable_ のように相互排他的です。関数が宣言された reliable は、必ず順序どおりに実行されます。関数が宣言された unreliable は、目的地に到達しない可能性があります。つまり、ネットワークが飽和状態になっていると、この関数呼び出しは破棄されます。

複製処理文に関するガイドライン


複製処理文は簡素なものにしてください。このクラスに関連したインスタンスがたくさんあると、これらの複製状態が極めて頻繁に実行される可能性があるため、許容されている最適化の実行には長時間かかります。ここまで、あまりに複雑なことは行わないよう強調してきましたが、ここでもこの原則に従ってください。次に、可能であれば bNet... 変数を使用します。 bNetInitialbNetOwnerbSimulatedPawn= などの変数は便利なだけでなく、負荷もかかりません。これらの変数は自動的に送信されるため、追加の CPU に課せられる要件は変化しません。また、Role/RemoteRole が SimulatedProxy または DumbProxy のいずれであるかに応じて、チェックを実行してさまざまな動作を実行できます。これらの複雑なチェックの例を確認する最適な場所は、エンジンクラス、特に ActorPawnPlayerController です。また、当然のことながら、いかなる複製処理文も変更してはなりません。複製処理文で i++ を実行すると、複製中に処理文によって*i* が予期せぬ形で変更されてしまい、意図しているものと別の結果が生じてしまいます。最後のアドバイスとして、サーバーは受信データのすべてが正規のものであるかどうかチェックします。クライアントが何か (変数または関数) をサーバーに複製すると、サーバーは Role および RemoteRole 変数を一時的に交換し、複製状態を評価して、そのデータを送信する妥当な理由が接続先にあるかどうか確認します。チェックに失敗すると、データ (変数または関数呼び出し) は破棄されます。そのため、複製処理文の書き込み時には、複製チェックを実行するために必要なデータがサーバー側にもすべてそろっていることを確認することが必要です。これが不可能だと、サーバーによって処理または承認されることはありません。

複製処理文の書き込み


UnrealScript では、どのクラスにも 複製ブロックが 1 つ付いており、この中に多くの複製処理文が含まれています。それぞれの複製処理文は、複製条件 (True または False のいずれであるかを評価するための処理文) 、そして条件が適用されることになる 1 つまたは複数の変数のリストから構成されています。

ただし、クラスに複製処理文が含まれていなくてもまったく問題ありません。この場合、クラスは定義済み変数を接続先に複製しないだけです。事実、たいていのクラスは複製処理文を必要としません。これは、表示に影響を及ぼすような「重要な」変数はアクタクラス内で定義されており、これらはサブクラスにおいてコードでしか修正できないためです。

クラスで新しい変数を定義しても、複製定義にリストしない場合、その変数は絶対に複製されません。一般的に見て、大半の変数は複製を必要としません。

複製処理文の UnrealScript 構文の例を以下に記します。これはポーンのクラスから取得したものです。

Pawn.uc
  replication
  {
    // Variables the server should send ALL clients.
    if (bNetDirty && Role == ROLE_Authority)
    FlashLocation, bSimulateGravity, bIsWalking, PlayerReplicationInfo, HitDamageType, TakeHitLocation, DrivenVehicle, Health;
  
    // variables sent to owning client
    if (bNetDirty && bNetOwner && Role == ROLE_Authority)
      InvManager, Controller, GroundSpeed, WaterSpeed, AirSpeed, AccelRate, JumpZ, AirControl;
  
    // sent to non owning clients
    if (bNetDirty && !bNetOwner && Role==Role_Authority)
      bIsCrouched, FlashCount, FiringMode;
  
    // variable sent to all clients when Pawn has been torn off. (bTearOff)
    if (bTearOff && bNetDirty && Role == ROLE_Authority)
      TearOffMomentum;
  
    // variables sent to all but the owning client
    if (!bNetOwner && Role==ROLE_Authority)
      RemoteViewPitch;
  }
  

これは、コントローラのクラスから取得した、一部の複製関数の例です。

Controller.uc
  reliable server function ServerRestartPlayer()
  {
    if (WorldInfo.NetMode != NM_Client && Pawn != None)
    {
      ServerGivePawn();
    }
  }
  
  reliable client function ClientSetWeapon( class<Weapon> WeaponClass )
  {
    local Inventory Inv;
  
    if (Pawn == None)
    {
      return;
    }
  
    Inv = Pawn.FindInventoryType( WeaponClass );
    if (Weapon(Inv) != None)
    {
      Pawn.SetActiveWeapon(Weapon(Inv));
    }
  }