ホストマイグレーション
Unity Multiplayer の設定

Transport Layer API の使用

Unity の提供する高レベルのネットワーク API は、プレイヤーやネットワーク上の GameObject、その他ネットワークで必要となる機能を簡単に管理できるシステムを備えていますが、これに加えて “Transport Layer” と呼ばれる低レベル API も使用可能となっています。これにより、低レベルで自分のワーキングシステムを構築することが可能となっています。これは、より特殊な、あるいは高度な条件がゲームのネットワークに要求される場合に役に立つでしょう。

Transport Layer は、OS のソケットベースのネットワーキング上で機能する薄いレイヤーです。バイトの配列で表されるメッセージの送受信機能を備え、さまざまなケースに対応するために“quality of service(サービス品質)” を変更できるオプションを多数提供しています。Transport Layer は柔軟性とパフォーマンスに重点を置いたもので、UnityEngine.Networking.NetworkTransport クラス内の API で使用可能です。

Transport Layer は、ネットワーク通信の基本的な機能に対応しています。これには以下が含まれます。

  • 接続の確立
  • 異なる “quality of service(サービス品質)” による通信
  • フロー制御
  • 基数統計
  • リレーサーバー経由の通信やローカルディスカバリーなどの付加的サービス

Transport Layer は二つのプロトコルを使用することができます。全般的な通信には UDP、WebGL には WebSockets が使用されます。 Transport Layer を直接使用する場合、典型的なワークフローは以下のようになります。

  1. Network Transport Layer の初期化
  2. ネットワークトポロジーの設定
  3. ホストの作成
  4. 通信(接続およびメッセージの送受信)の開始
  5. 使用後はライブラリーを終了します。

Network Transport Layer の初期化

Network Transport Layer を初期化する場合、デフォルトの初期化(引数なし)にするか、あるいは、ネットワークレイヤーの全面的な挙動を制御するパラメーター(例:最高パケットサイズやスレッドのタイムアウト制限など)を提供するか、どちらかを選ぶことができます。

    // 引数無しで Transport Layer を初期化する (デフォルト設定)
        NetworkTransport.Init();
    // カスタム設定で Transport Layer を初期化する例
        GlobalConfig gConfig = new GlobalConfig();
        gConfig.MaxPacketSize = 500;
        NetworkTransport.Init(gConfig);

上記の二つ目の例では、Transport Layer は、値が 500 にカスタム設定された “MaxPacketSize” を以って初期化されています。カスタムの Init 値は、特殊なネットワーク環境を使用していて且つ必要な設定を明確に理解している場合にのみお使いください。基本的には、インターネットを介してプレイする典型的なマルチプレイヤーゲームの開発の場合、引数なしのデフォルト Init() 設定が適切です。

設定

次のステップは、ピア間の接続の設定です。異なる通信チャンネルをいくつか定義する必要があるかもしれません。各チャンネルのサービス品質レベルは、送りたい特定のメッセージのタイプや、ゲーム中におけるそれらの相対的な重要度に合うように設定します。

    ConnectionConfig config = new ConnectionConfig();
        int myReiliableChannelId  = config.AddChannel(QosType.Reliable);
        int myUnreliableChannelId = config.AddChannel(QosType.Unreliable);

上記の例では、サービス品質レベルの値の異なる二つの通信チャンネルを定義しています。“QosType.Reliable” はメッセージを配信し、それが確実に届くようにします。“QosType.Unreliable” はメッセージが届く保証はしませんが、より速く送信されます。

また、ConnectionConfig オブジェクトのプロパティーを調整することで、コンフィグ設定を各接続ごとに行うことも可能です。ただし、あるクライアントから他のクライアントへの接続を行う場合、両方のピアで設定を同じにしないと、エラー CRCMismatch により接続に失敗してしまいます。

トポロジー

ネットワーク設定の最後のステップは、トポロジー定義です。ネットワーク トポロジーは、接続可能な回線の最大数および、使用される接続設定を定義します。

HostTopology topology = new HostTopology(config, 10);

ここでは、10 まで接続可能なトポロジーを作成しました。それぞれが前の手順で定義されたパラメーターによって設定されます。

ホストの作成

準備がすべて完了したので、ホスト (未接続のソケット) を作成します。

int hostId = NetworkTransport.AddHost(topology, 8888);

ここでは、新しいホストをポート 8888 と任意の IP アドレスに追加します。 このホストは最大 10 の接続をサポートし、各接続は config オブジェクトで定義したパラメーターを持ちます。

通信

When the host is created, we can start our communication. To do this we send different commands to the host and check its status. There are 3 main commands that we can send:

connectionId = NetworkTransport.Connect(hostId, "192.16.7.21", 8888, 0, out error);
NetworkTransport.Disconnect(hostId, connectionId, out error);
NetworkTransport.Send(hostId, connectionId, myReiliableChannelId, buffer, bufferLength,  out error);
  1. 最初のコマンドは、IP アドレス 192.16.7.21 とポート 8888 でピアに接続リクエストを送信します。ピアはこの接続に割り当てられた ID を返します。
  2. 2 番目は接続を切るリクエストです。
  3. 3 番目は、myReiliableChannelId と等しい ID を持つ信頼性の高いチャンネルを使用して、connectionId と等しい ID で接続にメッセージを送信します。メッセージは buffer[] に格納され、メッセージの長さは bufferLength で定義されます。

ホストの状態を確認するには、以下の 2 つの関数を使用できます。

NetworkTransport.Receive(out recHostId, out connectionId, out channelId, recBuffer, bufferSize, out dataSize, out error);
NetworkTransport.ReceiveFromHost(recHostId, out connectionId, out channelId, recBuffer, bufferSize, out dataSize, out error);

どちらもイベントを返します。最初の関数は、任意のホストからのイベントを返します (そして recHostId を通してホスト ID を返します)。 2 番目の形式は、id が recHostId のホストを確認します。Update() メソッド内でこれらの関数を使用できます。

void Update()
{
    int recHostId; 
    int connectionId; 
    int channelId; 
    byte[] recBuffer = new byte[1024]; 
    int bufferSize = 1024;
    int dataSize;
    byte error;
    NetworkEventType recData = NetworkTransport.Receive(out recHostId, out connectionId, out channelId, recBuffer, bufferSize, out dataSize, out error);
    switch (recData)
    {
        case NetworkEventType.Nothing:         //1
            break;
        case NetworkEventType.ConnectEvent:    //2
            break;
        case NetworkEventType.DataEvent:       //3
            break;
        case NetworkEventType.DisconnectEvent: //4
            break;
    }
}
  • ポイント 1: 特にイベントは何も返されていません。
  • ポイント 2: 接続イベントが届きました。これは新しい接続かもしれないし、前回の接続コマンドへの反応かもしれません。
myConnectionId = NetworkTransport.Connect(hostId, "192.16.7.21", 8888, 0, out error);
NetworkEventType recData = NetworkTransport.Receive(out recHostId, out connectionId, out channelId, recBuffer, bufferSize, out dataSize, out error);
switch (recData)
{
    case NetworkEventType.ConnectEvent: 
        if(myConnectionId == connectionId)
            //有効な接続リクエストが承認されました
        else
            //誰かが自分に接続しています
        break;
    //...   
}
  • コメント 3: データが返されました。 この場合、recHostId はホストを定義し、connectionId は接続を定義し、channelId はチャンネルを定義し、dataSize は受信したデータのサイズを定義します。recBuffer がデータを格納するのに十分な大きさであれば、データはバッファーにコピーされます。 そうでない場合、エラーに MessageToLong エラーが含まれ、バッファーを再割り当てしてこの関数を再度呼び出す必要があります。
  • コメント 4:切断信号が返されました。成立した接続が切断されたか、接続リクエストが失敗したという信号です。
myConnectionId = NetworkTransport.Connect(hostId, "192.16.7.21", 8888, 0, out error);
NetworkEventType recData = NetworkTransport.Receive(out recHostId, out connectionId, out channelId, recBuffer, bufferSize, out dataSize, out error);
switch (recData)
{
    case NetworkEventType.ConnectEvent: 
        if(myConnectionId == connectionId)
            //有効な接続リクエストが承認されました
        else
            //誰かが自分に接続しています
        break;
    //...   
}

WebGL の対応

WebSocket on client is supported. For the client side, all the steps described above (including topology and configuration) should be the same. Web clients can connect to the server only, where the server is a standalone player (Win, Mac or Linux only). On the server you should call

無効な IP または ポート

IP アドレスがリスニングアドレスである場合、IP アドレスに null を渡すことができます。ここではホストはすべてのネットワークインターフェースをリッスンします。サーバーが対応できる Websocket Host はひとつだけで、同時に一般的なホストを扱うこともできます。

NetworkTransport.AddWebsocketHost(topology, 8887, null);
NetworkTransport.AddHost(topology, 8888);

これは ウェブソケットプロトコルを扱う tcp ソケットを 8887 ポートで開き、一般的なプロトコルを扱う udp ソケットは 8888 ポートを開きます。

ホストマイグレーション
Unity Multiplayer の設定