ネットワークシステムにはネットワークを通してアクションを実行する方法が用意されています。この手のアクションはリモートプロシージャコール(RPC)と呼ばれることがあります。ネットワークシステムの RPC には2種類あります。まず、コマンド(Command)。これはクライアントから呼び出し、サーバー上で実行するものです。そして、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<Rigidbody2D>();
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 を送信するには、クライアントにあるプレイヤーオブジェクトではない、オブジェクトのインスタンスがサーバー上で実行される必要があります。
ClientRpc はサーバー上のオブジェクトからクライアントのオブジェクトへと送信されます。この呼び出しはどのサーバーオブジェクトからでも、生成された NetworkIdentity を伴って送信することができます。サーバーには優先度があるので、ClientRpc を発行できるサーバーオブジェクトにセキュリティ上の懸念点はありません。関数を 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);
}
}
LocalClient を伴ってホストとしてゲームを実行する場合、ClientRpc は LocalClient 上で実行されます。たとえ、同じプロセス上にある場合であってもサーバーを経由しているかのように扱われます。そのため、LocalClient と RemoteClient の振る舞いは ClientRpc に対して同じものになります。
Commands と ClientRpc の呼び出しで渡す引数は、シリアル化されネットワークを介して送信します。引数として渡せるものは
リモートアクションの引数に、スクリプトのインスタンスや Transform のようなゲームオブジェクトのサブコンポーネントを渡すことはできません。ネットワークを介してシリアル化できない、他の型もできません。