Version: 2017.2
遠隔手続き
オブジェクトの可視性

プレイヤー オブジェクト

ネットワークシステムの HLAPI において、プレイヤーはオブジェクトの中でも特別なものに区分されます。それらはサーバー上のプレイヤーを表現する役割を担い、プレイヤーのクライアントからコマンドを実行する能力を有しています(これはセキュリティ上安全なクライアント・サーバー間の遠隔手続き的な呼び出しです)。権威サーバーシステムでは、その他のプレイヤーではないサーバー側のオブジェクトはクライアント側のオブジェクトからの直接的なコマンドは受け取ることができません。これはセキュリティのためでもありますし、配置された環境で動作させることの複雑さを低減させるためでもあります。プレイヤーを通したユーザーからのコマンドすべてを経路制御することで、これらのメッセージが正しい位置、正しいクライアントから送信されていることが保障され、中心地での取り扱いが可能になります。

NetworkManager を使用しているときクライアントがサーバーに接続するとデフォルトでプレイヤーが追加されます。しかし一定の条件下では、プレイヤーの追加はある入力イベントが起こるまで延期されるのが望ましいこともあります。そのため、NetworkManager の AutoCreatePlayer チェックボックスを外して自動生成を切ることができます。プレイヤーが追加されると、NetworkManager は PlayerPrefab からオブジェクトをインスタンス化し、接続と関連付けます。この動作は NetworkManager の NetworkServer.AddPlayerForConnection を呼び出すことで実行されます。そして、NetworkManager.OnServerAddPlayer を上書きすることで修正できます。OnServerAddPlayer の通常の実装は PlayerPrefab から新規プレイヤーインスタンスを生成し、新しいプレイヤーインスタンスを生成するために NetworkServer. AddPlayerForConnection を呼び出すことです。OnServerAddPlayer をカスタマイズするのであれば NetworkServer. AddPlayerForConnection も呼び出さなければなりません。しかし、他に必要な初期化を実行するのも自由です。以下はプレイヤーの色をカスタマイズする例です:

class Player : NetworkBehaviour
{
    [SyncVar]
    public Color color;
}

class MyManager : NetworkManager
{
    public override void OnServerAddPlayer(NetworkConnection conn, short playerControllerId)
    {
        GameObject player = (GameObject)Instantiate(playerPrefab, Vector3.zero, Quaternion.identity);
        player.GetComponent().color = Color.red;
        NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
    }
}

NetworkServer. AddPlayerForConnection 関数は OnServerAddPlayer 内から呼び出される必要はありません。オブジェクトが正しく接続され、playerControllerId を介してさえいれば、OnServerAddPlayer が値を返した後に呼び出すことが可能になります。これにより、リモートデータソースからプレイヤーデータをロードするなど、非同期ステップの発生を可能にします。

HLAPI はプレイヤーとクライアントを別のオブジェクトとして扱います。ほとんどの場合、クライアントごとに単一のプレイヤーが存在するものです。しかし、コンソールシステムに複数のコントローラーが接続している場合などにおいては、一つの接続に対して複数のプレイヤーオブジェクトが存在することがありえます。一つの接続に複数のプレイヤーが存在する場合、playerControllerId プロパティーはそれぞれを区別するために使用されます。これは接続に焦点を当てた識別子なのです。クライアント上のプレイヤーと関連付けられたコントローラーの ID を文字通りマッピングします。

サーバー上の NetworkServer.AddPlayerForConnection に渡されたプレイヤーオブジェクトはシステムにより自動的に生成されます。そのため、NetworkServer.Spawn をプレイヤーのために呼び出す必要はありません。一度プレイヤーの準備が整えば、シーン内の有効な NetworkIdentity オブジェクトはプレイヤーのクライアントで生成されます。そのため、ゲーム内のネットワーク上にあるオブジェクトはすべてクライアントの最新の状態を用いて作成されます。結果、ゲーム内の他の参加者と同期が可能となります。

NetworkManager 上の playerPrefab はプレイヤーオブジェクトを作成するのに使用する必要はありません。他のプレイヤーを作成するのにそれぞれ別のメソッドを使用することも可能です。

AddPlayerForConnection 関数は OnServerAddPlayer 内から呼び出す必要はありません。この関数は非同期的に呼び出すことができます。プレイヤー作成方法に関する情報を返すデータベースなど、他のサービスへとリクエストを送る時のような感じです。

準備ステート

プレイヤーに加え、クライアントの接続には “準備” ステートも存在します。準備の整ったクライアントには生成されたオブジェクトとステート同期の更新が送信されます。一方で、準備の整っていないクライアントにはこれらの更新は送信されません。クライアントからサーバーへの初回接続ときこの準備は整っていません。この状態が続いている間、クライアントはサーバーとのリアルタイムインタラクションを必要としないことを実行できます。たとえば、シーンのロード、アバターの選択や、ログインボックスを埋めることなどが該当します。ひとたびクライアントがすべてのゲーム実行前作業を終え、アセットをすべてロードすれば、準備ステートへ移行するために ClientScene.Ready を呼び出すことができます。上記のシンプルな例は、NetworkServer.AddPlayerForConnection を用いたプレイヤーの追加でも同様にクライアントを準備ステートへと進めます。こちらでは準備が完了しているかは考慮されません。

クライアントは準備できているかに関わらずネットワークメッセージを送信、受信することができます。これは、有効なプレイヤーを用意する必要もないという意味でもあります。そのため、メニュー、または選択スクリーンに存在するクライアントはプレイヤーオブジェクトが存在するかどうかに関わらずゲームへと接続し、相互干渉することができます。この後には、コマンドや RPC 呼び出しを使用せずにメッセージを送信することに関したドキュメントが用意されています。

プレイヤーの切り替え

接続に使用するプレイヤーオブジェクトは NetworkServer.ReplacePlayerForConnection を使用して変更することができます。この機能はゲーム開始前のロビースクリーン表示時など、特定の期間におけるプレイヤーからのコマンド発行を制限するのに便利です。この関数は AddPlayerForConnection と同じ引数を取りますが、すでに接続しているプレイヤーへも使用することができます。変更前のプレイヤーオブジェクトを破棄する必要はありません。NetworkLobbyManager は、ロビー内すべてのプレイヤーで準備が完了している場合、この方法を用いて LobbyPlayer をゲームで使用するプレイヤーへと切り替えます。

この機能はプレイヤーオブジェクトが破壊された後に再生成する際にも使用することができます。単にオブジェクトを無効にして、再生成時に属性をリセットするよりもこの方法の方がよい場合もあります。実際に新しいオブジェクトと入れ替える際には以下のようなコードを使用できるでしょう:

class GameManager
{
    public void PlayerWasKilled(Player player)
    {
        var conn = oldPlayer.connectionToClient;
        var newPlayer = Instantiate(playerPrefab);
        Destroy(oldPlayer.gameObject);
    
        NetworkServer.ReplacePlayerForConnection(conn, newPlayer, 0);
    }
}

プレイヤーオブジェクトの接続が断たれた場合、クライアントは Command を実行できなくなります。しかしネットワークメッセージは依然として送信することができます。

ReplacePlayerForConnection を使用するためにはプレイヤーのクライアントがオブジェクトとクライアント間の関係を確立しておく必要があり、そのためには NetworkConnection オブジェクトを用意しておかなくてはなりません。これは通常 NetworkBehaviour クラスの connectionToClient プロパティーで確認できますが、変更前のプレイヤーがすでに破棄されている場合、容易に使用することはできないかもしれません。

接続を探すために、いくつか使用可能なリストがあります。NetworkLobbyManager を使用している場合、ロビープレイヤーは lobbySlots で使用することができます。また、NetworkServer では connectionslocalConnections のリストが保管されています。

遠隔手続き
オブジェクトの可視性