25
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

UNETメモ

Last updated at Posted at 2017-04-24

次の記事
UNETのNetworkBehaviourクラスのコールバックとコンテキストフラグの罠

はじめに

Unityのマルチプレイヤー関連の機能(通称UNET)についての備忘録。

ネットワークシステムの概念

ネットワークシステムの概念(公式のマニュアル)

クライアント

  • リモートクライアント
  • ローカルクライアント

の2種類があってホストとして動作してる場合はローカル、それ以外はリモート。どっちなのかはほぼ気にする必要なし。

自分に権限がある場合は[Command]つきメソッドの呼び出しでサーバに処理を実行させることができる。

サーバ

オブジェクトの同期の要。

  • NetworkManager.Spawn()で全クライアントで同期するオブジェクトの生成
  • [SyncVar]の値を各クライアントに同期
  • [ClientRpc]でクライアント側の処理呼び出し

クライアントに権限があるオブジェクトを操作するとクライアントに上書きされるらしい。

ホスト

ローカルクライアントとサーバが同じ場所で動いている状態。クライアントとサーバの両方のコードが動作するので非常にデバッグしづらい。

ネットワーク関連の属性(Attribute)

流れを理解するには公式の図が一番わかりやすい気がする。

alt

[SyncVar]

SyncVars(公式のマニュアル)

  • NetworkBehaviourコンポーネントのメンバー変数につける
  • サーバーから各クライアントへ値が同期される
    • (逆をやりたい場合は[Command]を使ってクライアントからサーバに送る)
  • int,string,float,Vector3構造体などで使用可
  • セッター内で変更しようとすると無限ループになるから同期が機能しないようになるっぽい
  • リストバージョンのSyncListもある。こちらは[SyncVar]不要。
    • SyncListString
    • SyncListFloat
    • SyncListInt
    • SyncListUInt
    • SyncListBool

[Client] [Server]

メソッドにつけるとそれぞれの環境でしか動作しなくなる。具体的には[Client]が付与されたメソッドはサーバ上では空実装になる(呼び出し時にWarningが表示される)。

[ClientCallback] [ServerCallback]

基本的に[Client] [Server]と同じだがWarningを発生しない。Start()とかUpdate()とかUnityに自動で呼ばれるメソッドにつける。

[Command]

クライアント側で呼び出し、サーバ側で実行したいメソッドにつける。メソッド名にはCmdのプレフィックスが必要。

以下の場合に使う。

  • クライアントからサーバへ値の送信
  • プレイヤーの操作をサーバへ送信
  • etc..

自分に権限がない場合は呼び出してもWarningを吐くだけ。staticメソッドにはつけられない(コンパイル時にエディタがエラーを吐く)。

uGUIのボタンのOnClickコールバックに直接[Command]つきのメソッドを指定しても動かないので呼び出しを一回ラップする必要がある。

同様にクライアントで呼び出されるコールバックとして利用する時は関数をそのまま渡すとクライアントでの呼び出しとなってしまうので注意!

[ClientRpc]
public void RpcEnableControl()
{
    if (this.isLocalPlayer == false)
    {
        return;
    }

    ChatManager.OnSubmitAsObservable()
        // .Subscribe(CmdSpeak) <- 「Rpcがクライアントから呼び出された」と怒られる
        .Subscribe(body => CmdSpeak(body)) // 引数つきで呼び出す
        .AddTo(this);
}

[Command]
private void CmdSpeak(string body)
{
    ChatManager.Instance.RpcSpeak(this.name, body);
}

[ClientRpc]

サーバ側で呼び出し、クライアント側で実行したいメソッドにつける。メソッド名にはRpcのプレフィックスが必要。強い権限で実行されるのでセキュリティとか関係なし。全てのクライアントで実行される。

制限時間の経過などサーバからクライアントへの通知に使う。

こちらもstaticメソッドにはつけられない(コンパイル時にエディタがエラーを吐く)。

[TargetRpc]

5.4からのAPIらしい。特定のクライントのみで実行される以外は[ClientRpc]と同じ。

以下のコードはマニュアルから一部修正して引用。

using UnityEngine;
using UnityEngine.Networking;

public class Example : NetworkBehaviour
{
    [TargetRpc]
    public void TargetDoMagic(NetworkConnection target, int extra)
    {
        Debug.Log("Magic = " + (123 + extra));
    }

    [Command]
    void CmdTest()
    {
        TargetDoMagic(connectionToClient, 55);
    }
}

権限

NetworkIdentifierで誰に権限があるか指定、NetworkManager.Spawn()でスポーン(全クライアント上でInstantiate()され、以後同期)。自分に権限がないNetworkBehaviourは操作できない。

プレイヤーの場合は権限つきというだけでなく特別な意味を持ち、NetworkManager.Spawn()ではなくNetworkManager.AddPlayerForConnection()でスポーンさせる。

ネットワークコンテキストプロパティー

NetworkBehaviourクラスにあるネットワークコンテキストを判断するためのプロパティー。Inspectorにあるオブジェクトのプレビューウィンドウで値を確認できる。

  • isServer - オブジェクトがサーバー上で実行されていて、かつ、サーバー上で生成された場合は true。
  • isClient - クライアント上で実行されるオブジェクトの場合は true。
  • hasAuthority - ①クライアント && ②自分に操作権限があるオブジェクト なら true。
  • isLocalPlayer - ①hasAuthority && ③プレイヤーオブジェクト なら true。

上2つは条件を満たしていてもそれぞれ

  • OnStartServer()
  • OnStartClient()

が呼ばれるまではfalseになっていて(参考リンク)、Hostの場合は両方trueになる。

NetworkBehaviourNetworkIdentity

以下の制約がある。

  • 両方ともSpawn可能なプレハブのルートであるゲームオブジェクトにアタッチする必要がある。
  • ルートオブジェクトにNetworkIdentityがないとNetworkManagerに登録できない。

データ同期の機能はNetworkBehaviourが持っているので、ルートでないGameObjectで発火した同期が必要なイベントはルートまで通知をバブリングなりする必要がある(これで詰まった)。

それが嫌なら別でプレハブ(ルートにNetworkBehaviourNetworkIdentityつき)を用意して、サーバ側でNetworkServer.SpawnWithClientAuthority()を呼び出して権限付きでスポーンさせる。

// NOTE: NetworkBehaviourを継承しているクラスにおける実装を想定

[Command]
void CmdSpawn()
{
    var go = (GameObject)Instantiate(
       otherPrefab, 
       transform.position + new Vector3(0,1,0), 
       Quaternion.identity);
       
    NetworkServer.SpawnWithClientAuthority(go, connectionToClient);
}

NetworkManager

HLAPIをより簡単に使えるようにいろいろ提供している一つの実装にすぎない。使い方がわかったらこのクラスを継承して自前のクラスを作るのが良さそう。


適当にまとめたのに長い

一旦ここまで。

参考資料

感想

前触った時はモバイルとブラウザで同じサーバで遊べなかったけどどうなったんだろうか。

次の記事
UNETのNetworkBehaviourクラスのコールバックとコンテキストフラグの罠

25
25
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?