Version: 2017.1
ネットワークのクライアントとサーバー
Transport Layer API の使用

ホストマイグレーション

専用サーバーなしのマルチプレイヤー・ネットワークゲームでは、ゲーム中のピアのひとつがゲーム権限の中枢として機能します。このピアのことをホストと呼びます。このピアがサーバーと「ローカルクライアント」を実行するのに対し、その他のピアはそれぞれが「リモートクライアント」を実行します。

ホストが失われると、ゲームを続行することができません。ホストが失われるのは、プレイヤーがゲームを抜けた場合、ホストの処理が停止あるいはクラッシュした場合、ホストのマシンがシャットダウンされた場合、ホストのネットワーク接続が切れた場合などです。

「ホストマイグレーション」機能を使用すると、リモートクライアントのひとつを新しいホストにすることができるので、マルチプレイヤーゲームを継続させることが可能になります。

仕組み

ホストマイグレーションが有効になっている場合、マルチプレイヤーゲームを実行中に、ピアのアドレスがゲーム中のピアに分配されます。ホストが失われると、ピアのひとつが新しいホストになり、その他のピアが新しいホストに接続されて、ゲームが継続されます。

新しい NetworkMigrationManager コンポーネントは、Unity Networking HLAPI を使用するマルチプレイヤーゲームにドロップすることが可能です。これによって、元々のホストが失われても新しいホストが設定されてゲームが継続可能になります。以下はエディター インスペクターの NetworkMigrationManager のスクリーンショットです。ここに現在のマイグレーションの状態が表示されます。

Network Migration Manager コンポーネント
Network Migration Manager コンポーネント

NetworkMigrationManager によって、NetworkManagerHUD に似たシンプルなユーザーインターフェースが提供されます。このユーザーインターフェースはテストやプロトタイピングのためのものです。実際のゲームでのホストマイグレーションには、カスタムのユーザーインターフェースが実装され、また多くの場合、カスタムのロジック(ユーザーによる入力なしで新しいホストを自動的に選択するなど)も実装されます。

Network Migration Manager のプロトタイピング用 HUD
Network Migration Manager のプロトタイピング用 HUD

古いホストの接続が切れたりゲームを抜けたりしたためにマイグレーションが行われた場合でも、古いホストは、新しいホストのクライアントとしてゲームに再参加できます。

ホストマイグレーションが行われる際、シーン内のすべてのネットワーク オブジェクトの SyncVar と SyncList の状態が維持されます。これは、オブジェクトの、シリアライズされたカスタムデータについても同様です。

ホストが失われると、ゲーム中のすべてのプレイヤーオブジェクトが無効になります。別のクライアントが新しいホストで新しいゲームに再参加すると、そのクライアントに対応するプレイヤーがホスト上で再び有効化され、他のクライアント上でオブジェクトが再生成されます。したがって、どのプレイヤーの状態データも、マイグレーション中に失われることはありません。

(注) ホストマイグレーション中に保持されるのは、クライアントによって利用可能なデータのみです。サーバー上にしかないデータが存在する場合、新しくホストになるクライアントはそのデータを利用することができません。したがって、SyncVar や SyncList に保存されていないホスト上のデータは、ホストマイグレーションが行われた後には利用不可能になります。

クライアントが新しくホストになると、コールバック関数 OnStartServer がすべてのネットワーク オブジェクトに実行されます。

新しいホスト上で、NetworkMigrationManager が関数 BecomeNewHost を使用して、現在の ClientSceneto の状態を元に、ネットワーク化されたサーバーシーンを構築します。

ホストマイグレーションが有効になったピアは、その connectionId によってサーバー上で識別されます。クライアントがゲームの新しいホストに再接続されると、この connectionId が新しいホストに渡され、古いホストに接続されていたクライアントにこのクライアントがマッチされます。この Id は ClientScene で “reconnectId” として設定されます。

非プレイヤー オブジェクト

ホストマイグレーションには、クライアント権限を持った非プレイヤー オブジェクトの処理も含まれます。プレイヤー オブジェクト同様、各クライアントが持つオブジェクトが、いったん無効化されたうえで再有効化されます。

ピアの識別

ホストが失われるまでは、すべてのピアはホストに接続されています。それぞれのピアが固有の connectionId をホスト上に持っています。この Id はホストマイグレーションにおいては “oldConnectionId” と呼ばれます。

新しいホストが選択されてピアがそのホストに再接続されると、各ピアによって “oldConnectionId” が提供されます。これはそれぞれのピアを識別するためのものです。これによって新しいホストは、再接続したクライアントを、対応するプレイヤーオブジェクトとマッチさせることができるようになります。

古いホストの使用は 0 の特別な oldConnectionId に再接続します - 古いホストへの接続を持っていなかったので、ホストは古いホストです。このために ClientScene.ReconnectIdHost があります。

ビルトインのユーザーインターフェースを使用する場合、oldConnectionId は自動で設定されます。これは NetworkMigrationManager.Reset あるいは ClientScene.SetReconnectId を使用して手動で設定することも可能です。

ホストマイグレーションの流れ

  1. マシン A が、ホストマイグレーションが有効になったゲームをホストする

  2. マシン B がクライアントを開始し、ホストマイグレーションが有効になったゲームに参加する
    • マシン B がピアの情報を受け取る(MachineA–0、 self (MachineB)–1)
  3. マシン C がクライアントを開始し、ホストマイグレーションが有効になったゲームに参加する
    • マシン B がピアの情報を受け取る (MachineA–0、 MachineB–1、 self (MachineC)–2)
  4. マシン A が失われる(したがってホストが失われる)

  5. マシン B のホストへの接続が切断される
    1. マシン B のコールバック関数がクライアント上で MigrationManager に実行される
    2. マシン B 上ですべてのプレイヤーのプレイヤーオブジェクトが無効になる
    3. マシン B はオンラインシーンに留まる
  6. マシン B がユーティリティー関数を使用して MachineB 自体を新しいホストとして選択する
    1. マシン B が BecomeNewHost() を呼び出す
    2. マシン B がリスニングを開始する
    3. マシン B の自身のプレイヤーオブジェクトが再アクティベートされる
    4. マシン B のプレイヤーが以前の状態を保持してゲームに戻りました。
  7. マシン C のホストへの接続が切断される
    1. マシン C のコールバック関数が、クライアント上で MigrationManager に実行される
    2. マシン C のプレイヤーオブジェクトが、すべてのプレイヤーに対して無効化される
    3. マシン C はオンラインシーンに残る
  8. マシン C がユーティリティー関数を使用して マシン B を新しいホストとして選択する
    • マシン C が新しいホストに再接続します
  9. マシン B が マシン C からの接続を受け入れる
    1. マシン C が、(AddPlayer メッセージではなく、) oldConnectionId で再接続メッセージを送信する
    2. サーバー上で MigrationManager にコールバック関数が実行される
    3. マシン B が、oldConnectionId を使用して、そのプレイヤーの無効になったプレイヤーオブジェクトを見付け、ReconnectPlayerForConnection() によってそれを再び追加する
    4. プレイヤー オブジェクトが マシン C 上で再生成される
    5. マシン C のプレイヤーが以前の状態を保持ししてゲームに戻りました。
  10. マシン A がゲームに戻る(古いホスト)
    1. マシン A がユーティリティー関数を使用して、新しいホストに マシン B を選択する
    2. マシン A が マシン B に「再接続」される
  11. マシン B が マシン A からの接続を受け入れる

  12. マシン A は 0 の oldConnectionId と再接続メッセージを送信します。
    1. サーバー(マシンB)上で MigrationManager にコールバック関数が実行される
    2. マシン B が oldConnectionId を使用して、そのプレイヤーの無効なプレイヤーオブジェクトを見付け、それをReconnectPlayerForConnection() で再び追加する
    3. マシン A でプレイヤーオブジェクトが再生成される
    4. マシン A のプレイヤーが以前の状態を保持してゲームに戻りました。

コールバック関数

NetworkHostMigrationManager のコールバック関数

//ホストへの接続を失った後に、クライアント上で呼び出されます。シーンを変更するかを制御します。 
protected virtual void OnClientDisconnectedFromHost(
    NetworkConnection conn, 
    out SceneChangeOption sceneChange)

// ホストへの接続を失った後に、ホスト上で呼び出されます。ホストはシーンを変更する必要があります。
protected virtual void OnServerHostShutdown()

//古いホストのクライアントがプレイヤーに再接続するとき、新しい ホスト (サーバー) 上で呼び出されます。
protected virtual void OnServerReconnectPlayer(
    NetworkConnection newConnection, 
    GameObject oldPlayer, 
    int oldConnectionId, 
    short playerControllerId)

// 古いホストのクライアントがプレイヤーに再接続するとき、新しい ホスト (サーバー) 上で呼び出されます。
protected virtual void OnServerReconnectPlayer(
    NetworkConnection newConnection, 
    GameObject oldPlayer, 
    int oldConnectionId, 
    short playerControllerId, 
    NetworkReader extraMessageReader)

// 古いホストのクライアントがプレイヤー以外のオブジェクトに再接続するとき、新しい ホスト (サーバー) 上で呼び出されます。
protected virtual void OnServerReconnectObject(
    NetworkConnection newConnection, 
    GameObject oldObject, 
    int oldConnectionId)

// ピアが更新されるときに、ホストとクライアントの両方で呼び出されます。
protected virtual void OnPeersUpdated(
    PeerListMessage peers)

//新しいホストを設定するために、ホストへの接続を失った後に、クライアント上のデフォルト UI によって呼び出されるユーティリティ関数 
public virtual bool FindNewHost(
    out NetworkSystem.PeerInfoMessage newHostInfo, 
    out bool youAreNewHost)

//プレイヤー以外のオブジェクトの許可が変わるときに呼び出されます
protected virtual void OnAuthorityUpdated(
    GameObject go,
    int connectionId,
    bool authorityState)

制約

サーバー(ホスト)のみに存在していたデータは、ホストの接続が切れると失われます。ホストマイグレーションが正常に実行されるためには、重要なデータを(サーバー上だけに保管するのではなく)クライアントに配信する必要があります。

上記は、ゲームが直接接続を使用している場合に当てはまる説明です。マッチメーカーやリレーサーバーを使用している場合には、追加の作業が必要となります。

ネットワークのクライアントとサーバー
Transport Layer API の使用