Unity の Netcode for GameObjects について調べたメモ
Netcode for GameObjects で自分が気になって調べたことをメモ代わりにまとめておく。
Netcode for GameObjects が何かとか、How to Use 系の記事は他にたくさんあるのでそのあたりは触れません。
参考にしたサイト
About Netcode for GameObjects | Unity Multiplayer Networking
Unity Netcode for GameObjectsを使ったオンラインマルチプレイゲーム開発Tips【Advent Calendar 12/23】|Colorful Palette
ClientRPC
ClientRpc | Unity Multiplayer Networking
サーバーは ClientRPC を実行することで(デフォルトで)全クライアントに対して命令を行える
- ClientRpcSendParameters を使えば特定のクライアントでのみ ClientRPC を実行可能
Host から ClientRPC を実行する場合は Host 自身もクライアントとして振る舞うため自身の ClientRPC も実行される
- 同じスタックで呼ばれるため無限ループにならないよう注意
宣言するには
[ClientRPC]アトリビュートをつけるのと、メソッド名にClientRpcプレフィックスをつけないといけない- それと前提として
NetworkBehavior継承のクラスにする必要がある
- それと前提として
特定のクライアントにのみ send したい場合は ClientRpcSendParameters を使う。以下公式からコピペ。
private void DoSomethingServerSide(int clientId)
{
// If isn't the Server/Host then we should early return here!
if (!IsServer) return;
// NOTE! In case you know a list of ClientId's ahead of time, that does not need change,
// Then please consider caching this (as a member variable), to avoid Allocating Memory every time you run this function
ClientRpcParams clientRpcParams = new ClientRpcParams
{
Send = new ClientRpcSendParams
{
TargetClientIds = new ulong[]{clientId}
}
};
// Let's imagine that you need to compute a Random integer and want to send that to a client
const int maxValue = 4;
int randomInteger = Random.Range(0, maxValue);
DoSomethingClientRpc(randomInteger, clientRpcParams);
}
[ClientRpc]
private void DoSomethingClientRpc(int randomInteger, ClientRpcParams clientRpcParams = default)
{
if (IsOwner) return;
// Run your client-side logic here!!
Debug.LogFormat("GameObject: {0} has received a randomInteger with value: {1}", gameObject.name, randomInteger);
}
ServerRPC
ServerRpc | Unity Multiplayer Networking
クライアントからサーバに情報を送信する際実行する RPC
- クライアントからしか送信できない&サーバーかホストしか受信できない
宣言には
[ServerRpc]アトリビュートと ServerRpc プレフィックスをメソッドにつける必要がある- NetworkBehavior 継承のクラスである必要がある
自身が NetworkObject のオーナーではない場合は ServerRpc の実行が許可されない
- しかし
[ServerRpc(RequireOwnership = false)]を宣言すれば任意のクライアントが ServerRpc を実行できるっぽい(以下公式をコピペ)
- しかし
[ServerRpc(RequireOwnership = false)]
public void MyGlobalServerRpc(ServerRpcParams serverRpcParams = default)
{
var clientId = serverRpcParams.Receive.SenderClientId;
if (NetworkManager.ConnectedClients.ContainsKey(clientId))
{
var client = NetworkManager.ConnectedClients[clientId];
// Do things for this client
}
}
public override void OnNetworkSpawn()
{
MyGlobalServerRpc(); // serverRpcParams will be filled in automatically
}
ServerRpcParams.Receive.SenderClientIdで Rpc を実行したクライアントの特定が可能- 他の引数がある場合は引数の最後に
ServerRpcParamsを宣言する必要がある - 以下の例ではクライアントが銃を打った時にクライアントの PlayerObject から lookWorldPosition に向けて Ray を打つサンプル(以下公式をコピペ)
- 他の引数がある場合は引数の最後に
[ServerRpc(RequireOwnership = false)]
public void PlayerShootGunServerRpc(Vector3 lookWorldPosition, ServerRpcParams serverRpcParams = default)
{
var clientId = serverRpcParams.Receive.SenderClientId;
if (NetworkManager.ConnectedClients.ContainsKey(clientId))
{
var client = NetworkManager.ConnectedClients[clientId];
var castRay = new Ray(client.PlayerObject.transform.position, lookWorldPosition);
RaycastHit rayCastHit;
if (Physics.Raycast(castRay, out rayCastHit, 100.0f))
{
// Handle shooting something
}
}
}
なお、RequireOwnership を false にしない場合は上の例で Vector3 引数だけ設定すれば良いらしい。
[ServerRpc]
public void PlayerOwnerShootGunServerRpc(Vector3 lookWorldPosition)
{
if (NetworkManager.ConnectedClients.ContainsKey(OwnerClientId))
{
var client = NetworkManager.ConnectedClients[OwnerClientId];
var castRay = new Ray(client.PlayerObject.transform.position, lookWorldPosition);
RaycastHit rayCastHit;
if (Physics.Raycast(castRay, out rayCastHit, 100.0f))
{
// Handle shooting something
}
}
}
- ホストで ServerRpc を実行したら自身の ServerRpc が実行されるので無限ループにならないよう注意が必要
NetworkVariable
NetworkVariable | Unity Multiplayer Networking
サーバとクライアント間で RPC など使わずに値の同期ができる仕組み
テンプレート
<T>の型の値のコンテナのラッパーなので、その値はNetworkVariable.Valueで取得するRpc との使い分け
- RPC vs NetworkVariable
- Rpc はその瞬間にのみ有用な一時的なイベントや情報を送受信したい時に使う
- 後から参加したプレイヤーにそれまで送られた Rpc が自動で送られることは無い
- NetworkVariable はずっと必要な永続的なステートや情報の同期に使う
最後に
Unity の Relay についても今度調査したい。まだベータ版。ベータ中は無料みたい。