UDN
Search public documentation:

PackagesAndNetworkingJP
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

パッケージおよびハイレベルの要素

ドキュメントの概要: ネットワーキングの観点から、関連するパッケージについての重要な情報。

ドキュメントの変更ログ: 最終更新者: Michiel Hendriks、Two.PackagesAndNetworking より移行。作成者: Mike Lambert (UdnStaff)

概要

Unreal Engine の編集に少しでも関われば、パッケージとはどのようなものかすぐに分かります。テクスチャ、マップ、コードなど、すべてのゲーム コンテンツはパッケージに格納されます。パッケージとは、色々な「要素」の集合にすぎません。パッケージには、マップ、テクスチャ、コード、サウンド、音楽、またはそれらの組み合わせを任意に格納できます。Unreal のディレクトリ構造では、誰でも簡単に整理できるように、テクスチャ、音楽、マップ用に場所が分けられています。そのため、マップ作成者はマップと同じディレクトリに .u ファイルを保存しなくても、テクスチャとコードをマップに含めることができます。ただし通常は、混乱しないように Unreal Engine が提供するサンプル セットに従うのが賢明といえます。マップには .umap (または独自のマップ拡張子)、コードには .u、その他の要素には .upk 拡張子を付けて、整理したディレクトリ内に適切に配置します。UnrealScript のコンパイル パフォーマンス向上のために推奨されていることの 1 つに、パッケージの分割があります。コード パッケージの中にゲーム テクスチャとモデルを含めずに、これらをコンパイルして、ダミー クラスを含むパッケージを作成します。これにより、アート関係のデータを事前に一度コンパイルしてから、コードの再コンパイルによってこれらのパッケージを単に参照することができます (#obj load exec 行を使用します)。もう 1 つの利点としては、パッチを小さなコード ファイルとして配布することができ、モデルやテクスチャを含むパッケージ全体を再度ダウンロードせずに済みます。

このドキュメントは Unreal のネットワーキング総括 の一部です。

ServerPackages

サーバが起動すると、ゲームに必要なすべてのパッケージを読み込みます。マップ、関連テクスチャ、サウンドおよび音楽パッケージを読み込み、servertravel コマンドの ?game=XX で定義されたゲームを読み込みます。 gamename .ini (ExampleGame.ini) で指定された serverpackages を読み込みます。これらのパッケージやクラスの読み込みが完了した後は、サーバに格納されたこのパッケージ リストにはパッケージは追加されません。この、serverpackages リストと呼ばれるリストは、サーバに接続するすべてのクライアントに送信されます。次に、クライアントは各自でこれらのパッケージを読み込み、クライアントに送信されたアクタを支障なく読み込めるようにします。これらのパッケージがすべて読み込まれるまで、コードは実行されません。これがサーバの場合は、パッケージの読み込みが完了するまでクライアントの接続を受け入れません。Unreal でレベルまたはサーバを読み込む際の非応答遅延が長いのは、このような理由によるものです。DynamicLoadObject() を使用して追加パッケージを読み込むことは可能ですが、この方法ではパッケージはローカル マシンにしか読み込まれません。接続する他のマシンは、これらのパッケージを読み込むよう指示されません。レベルの読み込みに必要はすべてのパッケージは、パッケージ マップに自動的に追加されます。

パッケージの読み込み方が原因で、不思議な現象が発生することがあります。このような例の 1 つとして、ここではミューテーターを取り上げて説明します。ミューテーター自体に関心がない方も、他の場所で同様の問題が出現する可能性があることから、この例を一読されることをお勧めします。UnrealScript では、GameInfo's InitGame() の DynamicLoadObject() を使用してミューテーターを読み込みます。これはパッケージのリストが読み込まれた後に発生するため、この時点ではミューテーター パッケージは serverpackages に読み込まれていません。Unreal 提供のミューテーターはゲームコード自体に格納されているので、この問題とは関係がありません。ミューテーターがサーバ側のみで動作する場合も、そのパッケージ内のアクタをクライアントに送信する必要がないので問題ありません。しかし、アクタをクライアントに送信するようにミューテーターで定義されている場合、このアクタがクライアントに見えないという問題が発生します。このパッケージは serverpackages に追加されていないので、クライアントで読み込まれません。そのためクライアントはアクタのデフォルト プロパティを知ることもなく、表示もできないという訳です。この問題を解決するには、 gamename .ini ファイルの [Engine.GameEngine] の下にある serverpackages 配列に、問題のミューテーターを明示的に配置します。これにより、ゲームの開始前にミューテーター パッケージが読み込まれます。後から GameInfo が同じパッケージを読み込むときには既に serverpackages に含まれているので、結果としてクライアント側でも正常に機能します。

同じ問題はスキン パッケージにも当てはまります。ユーザーのスキンはコマンドライン オプションの連結によって指定され、GameInfo の Login が実行されるまで読み込まれません。上記の例と同じで、これもすべての serverpackages が読み込まれた後です。そのため、各クライアントにはこのテクスチャが複製されますが、クライアントが表示しようとすると、テクスチャ パッケージがクライアントのローカル メモリにないので (serverpackages に含まれていないため)、悪名高いグリーン スキンの問題に遭遇することになります。

GUID

すべてのパッケージには、GUID (Globally Unique Identifier) が関連付けられています。パッケージを保存するときに GUID が生成されます。この GUID は、同じパッケージの異なるバージョンを識別したり、パッケージを区別する目的で使用されます。GUID は時間やその他の情報を取り入れて生成される 128 ビットの ID で、そのため 2 つの GUID が偶然同じになる可能性はまず皆無であるといえます。2128 = 2.4 x 1038 通りの GUID が生成可能です。これだけの数があれば、当面の間は心配無用でしょう。

Epic では GUID が偶発的に繰り返されないよう手段が講じられましたが、その後に、これを意図的に実行できる方法を編み出しました。ここでは詳細には触れませんが、パッケージの同調プロセスでは元のパッケージと同じ GUID が新規パッケージにも与えられ、それらの意図や目的が同じであると見なされるようにします。この理由については後半のセクションで説明します。

サーバへの接続

サーバへの接続プロセスは、概略として次のようになります。

  1. サーバは、各パッケージの GUID と共に serverpackage リストを送信します。(Engine/UnConn -> UNetConnection::SendPackageMap)
  2. サーバは [IpDrv.TcpNetDriver] の DownloadManagers 配列を調べて、クライアントによるパッケージのダウンロード方法を検出します。このリストをクライアントに送信します。(Engine/UnConn -> UNetConnection::SendPackageMap)
  3. クライアントは、[Core.System] -> Path 配列で定義されているディレクトリのリストを調べて、サーバから送信されたパッケージと同名のパッケージを探します。同じ名前のパッケージの GUID がサーバから送信されたものと一致することを確認し、一致しなければ "バージョンの不一致" エラーを発生させます。
  4. 上記のステップでクライアントが検出できなかったすべてのパッケージについて、クライアントは Cache ディレクトリ ([Core.System]CachePath および CacheExt で定義) を調べて、指定された GUID を持つパッケージを探します。
  5. まだ見つからないパッケージがあれば、それらをダウンロードする必要があります。パッケージがダウンロード可能であり (当該パッケージの packageflags で定義されています)、[IpDrv.TcpNetDriver]AllowDownloads でクライアントがダウンロードを許可していることを確認します。("WELCOME" の場合: Engine/UnPenLev -> UNetPendingLevel::NotifyReceivedText)
  6. クライアントはリストを順番に調べて、実際に存在するものが見つかるまでそれぞれのダウンロード マネージャを順に実行していきます。 (Engine/UnConn -> UNetConnection::ReceiveFile) 見つからない場合はデフォルトの Engine.ChannelDownload を使用します。次に、そのダウンロード方法をサーバに要求します。(Engine/UnConn -> UNetConnection::ReceiveFile))
  7. サーバはこの方法が許可されているかどうかを確認し、許可されている場合はどのように許可されているかを確認します。ユーザーが Engine.ChannelDownload を要求した場合: (Engine/UnDownload)
    1. サーバは、[IpDrv.TcpNetDriver]AllowDownloads の論理値が true かどうかを調べ、true の場合はファイルを送信しません。
    2. サーバはクライアントにファイルを送信します。特定のクライアントへのファイル送信に帯域幅が消費されるため、他のクライアントに遅れが発生する可能性があります。ファイルの最大送信速度は [IpDrv.TcpNetDriver] -> MaxClientRate で決定されます。
  8. パッケージのダウンロードをサーバが許可せず、そのためクライアントがダウンロードを実行できない場合、クライアントは操作を放棄し、サーバへの接続は失敗します。

パッケージの一致

パッケージを同調させる目的は、2 つのパッケージ バージョン間のネットワーク互換性を提供することにあります。これは次のように機能します。例えば、製品のバージョン 1 が既にリリースされていて、今からバージョン 2 をリリースするとします。この新規バージョンをのパッチを適用していないユーザーが、適用済みのサーバ上でプレイできなくなったり、逆にアップグレード済みのユーザーがまだパッチを適用していないサーバ上でプレイできなくなるという状態を回避するには、バージョンを同調させる必要があります。バージョンの同調により Unreal は 2 つのバージョンが同じであるかのように振る舞い、古いパッケージのユーザーはアップグレード済みのバージョン ユーザーとプレイすることができます。当然のことですが、パッケージの同調を行なうには、新規バージョンに古いバージョンの「振りをする」よう指図するため、同調の対象となる旧バージョンが存在しなければなりません。パッケージの同調には 2 つの方法があります。

  • ゲームのディレクトリ内の guires ディレクトリに、旧バージョンのコピーを置きます。これは通常 Binaries ディレクトリの次にあります。ucc make でコンパイルされたバージョンはすべて、guires に保存されたバージョンに自動的に同調します。
  • パッケージの新規バージョンをコンパイルします。次に、conform commandlet を使用してパッケージを同調させます。

パッケージをコンパイルすると、_Generations_ という名のパッケージに配列が格納されます。これは、パッケージの同調履歴を格納するパッケージです。(Core/UnObj -> UObject::SavePackage) バージョン 2 のサーバがバージョン 1 のクライアントに遭遇すると、Generations 配列のバージョン 1 を調べて、そのクライアントとの通信方法を理解します。

この方法は、同調相手の選択にも影響を及ぼします。バージョン 3 のパッケージを同調させるときには、バージョン 1 とバージョン 2 の両方に同調させるために、バージョン 3 をバージョン 2 と (1 ではなく) 同調させる必要があります。バージョン 2 には、バージョン 1 と 2 の両方との通信方法に関する情報が格納されています。バージョン 3 が 2 つのバージョンとの互換性を確保するにはこの情報が必要なので、バージョン 2 と同調させなければなりません。自分の管理下にはない、公開リリースとしてパブリック バージョンのコードをリリースする場合には、常にそのバージョンを自分の guires ディレクトリに配置しておき、次に内部でコンパイルする (最終的に公開リリースする) バージョンが、すべてのパブリック バージョンと互換性を維持できるようにするのが良策です。パッケージのすべてのバージョンは、初代バージョンではなく、その直前のバージョンと同調させる必要があります。それにより、バージョン 4 のクライアントがバージョン 2 のサーバと対面したときに、下位互換性を確保し、パッチが適用されていないサーバと通信する方法がわかります。(Core/UnCoreNet -> UPackageMap::Compute)

実際には、同調プロセスは名前テーブルの同期を保持する作業で構成されています。バージョン 2 をバージョン 1 に同調させると、バージョン 1 に現れたすべての名前の位置をそのまま保持した状態で名前テーブルが保存されます。バージョン 2 で現れる名前はすべて、このリストの後に追加されます。サーバやクライアントが関数または変数に関する情報が送信するときには、実際に名前テーブルにインデックスを送信します。したがって、例えばクライアントがバージョン 2 でサーバーがバージョン 1 であっても、通信に使用される名前テーブルが一致する限り、完璧な通信が実現します。generations 配列をディスクに保存するときには、名前の数とエクスポートの数を保存します。これにより、Unreal は名前テーブルの最初の X 個の項目(バージョン 1 に等しい数の項目) を使用し、バージョン 2 のパッケージがバージョン 1 のパッケージと通信できることを確認します。

ローカライズ パッケージの場合は、各言語が他のすべての言語と連動するように数珠つなぎ式に同調させることをお勧めします。例えば、'int'、'fra'、'esn' および 'deu' のローカライズ パッケージのバージョンがある場合、'int' と 'fra'、次に 'fra' と 'esn'、次に 'esn' と 'deu' のように同調していきます。言語の順番は特にありません。https://udn.epicgames.com/lists/showpost.php?list=unprog3&id=30760 を参照してください。

パッケージ フラグの警告

パッケージ フラグの中には、面白いだけでなく、必要なものがいくつかあります。ネットワークプレイにパッケージを使用し、クライアントによるパッケージのダウンロードを許可するには、パッケージの AllowDownload フラグをオンにする必要があります。PackageFlags の関連項目を参照してください。

パッケージの不一致エラー

名前が同じで GUID が異なるパッケージをダウンロードすると、パッケージの不一致エラーが発生します。このエラーを解決するには、同じパッケージの旧バージョンとこのパッケージを同調させます (つまり、新しい generation を作成します)。ただし、サーバが両方のパッケージのチェックサムの存在を知らなければ、不正処理の対応策が作動するので注意してください。