Version: 2020.3
言語: 日本語
操作と通信
NetworkManager コールバック

遠隔手続き

重要: UNet は非推奨のソリューションであり、新しい Multiplayer and Networking Solution (MLAPI) が開発途中です。詳細については、Unity MLAPI ウェブサイトの情報 を参照してください。

ネットワークシステムにはネットワークを通して処理を実行する方法が用意されています。このような処理は遠隔手続き呼出し (リモートプロシージャコール、RPC) と呼ばれることがあります。ネットワークシステムの RPC には2種類あります。まず、コマンド (Command)。これはクライアントから呼び出し、サーバー上で実行するものです。そして、クライアント RPC 呼び出し (ClientRpc)。これはサーバーから呼び出し、クライアント上で実行するものです。

以下のダイアグラムは遠隔手続きの動作の流れを示しています。

コマンド

コマンドはクライアントの操作するプレイヤーオブジェクトから、サーバー上にあるプレイヤーオブジェクトへと送信されるものです。セキュリティ上の理由で、コマンドは 自分自身の プレイヤーオブジェクトからのみ送信できます。そのため、他のプレイヤーを操作することはできません。関数をコマンドに導入するためには、カスタム属性 [Command] を追加し、「Cmd」プレフィックスを加える必要があります。これでこの関数はクライアントの呼び出しに応じてサーバー上で動作するようになります。どのような引数であれ、コマンドによって自動的にサーバーに渡されます。

コマンド関数にはプレフィックスの 「Cmd」を必ずつけなければなりません。このプレフィックスは、コマンドを呼び出すコードを見つける際のヒントなのです。つまり、この関数は特別で、通常の関数と同じローカル環境では実行されないということを表しています。

class Player : NetworkBehaviour
{

    public GameObject bulletPrefab;

    [Command]
    void CmdDoFire(float lifeTime)
    {
        GameObject bullet = (GameObject)Instantiate(
            bulletPrefab, 
            transform.position + transform.right,
            Quaternion.identity);
            
        var bullet2D = bullet.GetComponent();
        bullet2D.velocity = transform.right * bulletSpeed;
        Destroy(bullet, lifeTime);

        NetworkServer.Spawn(bullet);
    }

    void Update()
    {
        if (!isLocalPlayer)
            return;

        if (Input.GetKeyDown(KeyCode.Space))
        {
            CmdDoFire(3.0f);
        }

    }
}

クライアントからのコマンド送信は毎フレーム実行されることに注意してください。この影響で多くのネットワーク障害が起こる可能性があります。

通常、コマンドはチャンネル 0 で送信されます。これはデフォルトで使用する、信頼できるチャンネルです。そのため通常すべてのコマンドは確実にサーバーへと送信されます。チャンネルは [Command] カスタム属性の「Channel」パラメーターで変更することができます。パラメーターは Int 型で、チャンネル数を表します。

チャンネル 1 は、デフォルトでは信頼性の低いチャンネルとして設定されています。使用するには Command 属性のパラメーターで 1 を設定してください。以下のようになります。

    [Command(channel=1)]

Unity 5.2 からは、クライアント権限を持つノンプレイヤーのオブジェクトからコマンドを送信することが可能です。オブジェクトは NetworkServer.SpawnWithClientAuthority でスポーンされているか、NetworkIdentity.AssignClientAuthority で権限を付加する必要があります。これらのノンプレイヤー オブジェクトから送信された Commands は、クライアントに関連するプレイヤーオブジェクト上ではなく、オブジェクトのサーバーインスタンス上で実行されます。

クライアント Rpc

ClientRpc はサーバー上のオブジェクトからクライアントのオブジェクトへと送信されます。この呼び出しは、スポーンされた NetworkIdentity を持つすべてのサーバーオブジェクトから、送信することができます。サーバーには権限があるため、サーバーオブジェクトに対してセキュリティ上の問題なくこれらの呼び出しを送信することができます。関数を ClientRpc に加えるためには [ClientRpc] カスタム属性を加え、「Rpc」プリフィックスを付けてください。これで、この関数はサーバーで呼び出されると、クライアント上で実行されます。どのような 引数も自動的に ClientRpc でクライアントへと渡されます。

ClientRpc 関数にはプリフィックスの 「Rpc」を必ずつけなければなりません。このプリフィックスはメソッドを呼び出すコードを読み取る時のヒントなのです。つまり、この関数は特別で、通常の関数と同じローカル環境では実行されないということを表しています。

class Player : NetworkBehaviour
{

    [SyncVar]
    int health;

    [ClientRpc]
    void RpcDamage(int amount)
    {
        Debug.Log("Took damage:" + amount);
    }

    public void TakeDamage(int amount)
    {
        if (!isServer)
            return;

        health -= amount;
        RpcDamage(amount);
    }
}

ローカルクライアントを持つホストとしてゲームを実行する場合、ClientRpc の呼び出しはローカルクライアント上で発生します。たとえ、サーバーとして同じ処理を行ったとしても、です。そのため、ClientRpc に対するローカルクライアントとリモートクライアントの挙動は、同じになります。

遠隔手続きの引数

Command と ClientRpc の呼び出しで渡す引数は、シリアル化されネットワークを介して渡されます。引数として渡せるものは以下の通りです。

  • 基本型 (byte、int、float、string、UInt64、など)
  • 基本型の配列
  • 許可された型を含む構造体
  • Unity のビルトインの数学に関する型 (Vector3、Quaternion、など)
  • NetworkIdentity
  • NetworkInstanceId
  • NetworkHash128
  • NetworkIdentity コンポーネントがアタッチされたゲームオブジェクト

遠隔手続きの引数には、スクリプトのインスタンスや Transform のようなゲームオブジェクトの付属コンポーネントを使用できません。ネットワークを介してシリアル化できない、他の型も使用できません。

操作と通信
NetworkManager コールバック