【Strix】 PhotonからStrix Cloudに移行してみた ～マッチメイキング編～

今記事は以下の記事のマッチメイキング編です。

https://qiita.com/HarumaroJP/items/cf9034bcf7f5e73d2b5e

まだメインの記事を読んでない方はそちらから読んでいただけると幸いです。

Strix Cloudのルームの作成 & 入室までを解説していきたいと思います。

##ルームの作成
```C#
        void CreateRoom(
        RoomProperties roomProperties, //ルームプロパティ
        RoomMemberProperties memberProperties, //プレイヤー（メンバー）のプロパティ
        RoomCreateEventHandler handler, //成功時
        FailureEventHandler failureHandler, //失敗時
        RequestConfig config = null); //タイムアウト時間を設定できる。基本的に使わなくてもいい
```

実装例

```C#
        public static void CreateRoom(RoomProperties properties, string password) {
            properties.password = password;

            s_strixNetwork.CreateRoom(properties, new RoomMemberProperties() {
                name = StrixNetwork.instance.playerName,
            }, (_) => {
                Debug.Log($"Room Created!");
            }, (_) => {
                Debug.Log($"Room Create Failed!");
            });
        }
```
ルームプロパティとメンバープロパティを設定することで作成することができます。
ルームプロパティには作成したい部屋の情報、メンバープロパティには自分のプレイヤーの情報を設定します。

###ルームプロパティの作成方法

プロパティには以下の情報を設定できます。

|名前|型|説明|
|:-:|:-:|:-:|
|name|string|ルームの名前|
|capacity|int|プレイヤーの許容人数|
|password|string|パスワード（空の場合は誰でも入れる）|
|state|int|ルームの状態|
|isJoinable|bool|参加可能かどうか（falseの場合参加できない）|
|key1-key8|double|カスタムキー **必ずdouble型**|
|stringKey|string|カスタムの文字列キー|
|properties| Dictionary< string, object > |追加のカスタムプロパティ値|

```C#
        //Dictionaryから変換する方法
        var dictionary = new Dictionary<string, object> {
            {"name", "ルーム名"},
            {"capacity", 8}, //プレイヤーの許容人数
            {"password", ""},
            {"state", 0}, //部屋の状態など
            {"isJoinable", true}, //参加可能かどうか
            {"key1", (double) 2}, //カスタムキー（お好みで） 例：ゲームモード, マップキー
        };

        RoomProperties properties = new RoomProperties();
        properties.FromDictionary(dictionary); //Dictionaryからプロパティに変換

        //プロパティに直接設定する方法
        properties.name = "ルーム名";
        properties.capacity = 8;
        properties.state = 0;
        properties.isJoinable = true;
```

辞書に指定されたキーと一致する情報を登録して、プロパティに変換しています。
プロパティに直接設定する方法もありますが、前者のほうが見やすいのでおすすめです。


##ルームの参加
他にもありますが今回はこちらを使います。

```C#
    void JoinRoom(
    RoomJoinArgs args, //入りたいルームの情報
    RoomJoinEventHandler handler, //成功時
    FailureEventHandler failureHandler, //失敗時
    RequestConfig config = null) //タイムアウト時間を設定
```

ランダムに部屋に部屋に入るには

```C#
    void JoinRandomRoom(
    RoomMemberProperties memberProperties, //自身のプレイヤー情報
    RoomJoinEventHandler handler, //成功時
    FailureEventHandler failureHandler,  //失敗時
    RequestConfig config = null)
```
しかし上記の2つの関数は残念ながらちょっと使いづらいです、、
`JoinRoom`は入りたいルームの情報が必要で、参加前に検索する必要があります。
`JoinRandomRoom`は完全ランダムなので、条件を完全に無視して入れる部屋に入れてしまいます。

PUN2の`JoinRandomRoom`のような**指定した条件でランダムに参加する**を実現するには関数を自作する必要があります。
まずは参加前に部屋を検索してみましょう。

##ルームの検索

```C#
    void SearchJoinableRoom(
    ICondition condition, //検索の条件
    Order order, //検索結果の順序
    int limit, //検索結果の件数
    int offset,  //0の場合リストの最初から検索。（基本的に0）
    RoomSearchEventHandler handler, //成功時
    FailureEventHandler failureHandler, //失敗時
    RequestConfig config = null)
```

実装例

```C#
        //メンバー数が混雑していない順に並べる
        static Order orderAscending = new Order("memberCount", OrderType.Ascending);

        static void SearchRoom(ICondition con, Action<RoomInfo> successEvent, Action failureEvent) {
            s_strixNetwork.SearchJoinableRoom(con, orderAscending, 10, 0,
                args => {
                    //ICollectionで返ってくるためListに変換
                    List<RoomInfo> roomList = new List<RoomInfo>(args.roomInfoCollection);
                    if (roomList.Count == 0) {
                        failureEvent();
                        return;
                    }

                    //ルームをランダムで取得
                    RoomInfo info = roomList[Random.Range(0, roomList.Count)];
                    successEvent(info);
                }, args => { DebugEx.Log($"ルーム情報の取得に失敗しました！\n{args.cause.Message}"); });
        }
```

これでsuccessEventでルーム情報を取得できるのですが、RoomJoinArgsに変換する必要があるので後で説明します。

###検索する部屋の条件を設定する
条件を設定するには`ICondition`を作成する必要があります。
これは複雑な条件のクエリを構築できるインターフェースです。

まず、`ConditionBuilder`クラスでビルダーを作成します。
`Field()`で比較したいキーを指定し、`EqualTo()`比較する値を設定できます。

```C#
        IConditionBuilder builder;

        builder = ConditionBuilder.Builder() //ビルダーを作成
                                  .Field("capacity") //プレイヤーの許容人数が
                                  .EqualTo(6); //6と等しい場合
```
`EqualTo`以外にもその値以上、その値以下など複雑な条件を設定できます。
詳しくはドキュメントに載っているので確認してみてください。

https://www.strixengine.com/doc/unity/api/html/T_SoftGear_Strix_Client_Core_Model_Manager_Filter_Builder_FieldClauseBuilder.htm

条件を追加する場合は

```C#
        //～かつkey1が3よりも大きい場合
        builder.And().Field("key1").GreaterThan((double) 3);

        //～またはkey2が3よりも小さい場合
        builder.Or().Field("key2").LessThan((double) 1);   
```
メソッドを連結していくことで条件を追加することができます。


##条件でランダムに参加する

```C#
        static void JoinRandomRoom(ICondition con, RoomJoinEventHandler successEvent, FailureEventHandler failureEvent) {
            //指定した条件で部屋を検索
            SearchRoom(con, info => {
                //取得したらRoomJoinArgsにして接続できるようにする
                RoomJoinArgs args = new RoomJoinArgs() {
                    host = info.host,
                    port = info.port,
                    protocol = "TCP",
                    roomId = info.roomId,
                    memberProperties = new RoomMemberProperties() {
                        name = StrixNetwork.instance.playerName
                    }
                };

                s_strixNetwork.JoinRoom(args, successEvent, failureEvent);
            }, () => {
                DebugEx.Log("Room not found!");
            });
        }
```

これでPUN2の`JoinRandomRoom`を実現できました。
ちなみに、2021/07/23時点では**プロトコルはTCPのみ対応** なので注意してください。
ただ、Strixの技術力のおかげかPUN2のUDPとあまり差は感じなかったので、普通に使う分には問題なさそうです。

次回はStrixにおけるプレイヤーの扱いを解説します！
[【Strix】 PhotonからStrix Cloudに移行してみた ～プレイヤー編～](https://qiita.com/HarumaroJP/items/0d7e4b1b68faf5e765bd)

##参考リンク
公式ドキュメント

https://www.strixengine.com/doc/unity/guide/ja/unitysdk/matchmaking/gameloop/createroom.html

https://www.strixengine.com/doc/unity/guide/ja/unitysdk/matchmaking/gameloop/joinroom.html

https://www.strixengine.com/doc/unity/guide/ja/unitysdk/matchmaking/gameloop/searchroom.html

https://www.strixengine.com/doc/unity/guide/ja/unitysdk/matchmaking/gameloop/deleteroom.html