【Photon Unity Network】ルームのカスタムプロパティをちょこっと解説

# 記事の環境
Unity 2019.1.0f2
[Photon Unity Network](https://assetstore.unity.com/packages/tools/network/photon-unity-networking-classic-free-1786)(バージョン1.97)

# ルームのカスタムプロパティって？
端的に説明すると、**ルーム内で共有できるハッシュテーブル**です。

**(注：ハッシュテーブルとはC#で言うDictionaryのこと)**

# 使い方
```RoomPropertyTest.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RoomPropertyTest : MonoBehaviour
{
    // ハッシュテーブルを宣言
    ExitGames.Client.Photon.Hashtable roomHash;

    // ローカルで使っているハッシュをルームにセット
    public void SetRoomProperty()
    {
        // ハッシュに要素を追加(同じ名前があるとエラーになる)
        roomHash.Add("hoge", 0);

        // ハッシュに要素を追加、既に同じ名前のキーがあれば上書き
        roomHash["hoge"] = 1;

        // ルームにハッシュを送信する
        PhotonNetwork.room.SetCustomProperties(roomHash);
    }

    // ルームのハッシュが送信されたら、送信されたハッシュが入ってくる(Photonの機能で戻り値の型、関数名、引数を一致させると勝手に呼ばれる)
    public void OnPhotonCustomRoomPropertiesChanged(ExitGames.Client.Photon.Hashtable changedRoomHash)
    {
        // 変更されたハッシュを受け取る
        roomHash = changedRoomHash;
    }
}
```
# 説明
    // ハッシュテーブルを宣言
    ExitGames.Client.Photon.Hashtable roomHash;
【ExitGames.Client.Photon】とネームスペースから記述しているのはC#にもともとあるHashtableと区別するためです。

    public void SetRoomProperty()
    {
        // ハッシュに要素を追加(同じ名前があるとエラーになる)
        roomHash.Add("hoge", 0);

        // ハッシュに要素を追加、既に同じ名前のキーがあれば上書き
        roomHash["hoge"] = 1;

        // ルームにハッシュを送信する
        PhotonNetwork.room.SetCustomProperties(roomHash);
    }
次にSetRoomProperty関数ですが、これはまぁそのままですね。

このHashtableは**Dictionaryクラスをまんま継承している**ので使い方はDictionaryとなにも変わりません。

唯一目新しいのはこの部分でしょうか

    // ルームにハッシュを送信する
    PhotonNetwork.room.SetCustomProperties(roomHash);

ここでPhotonの機能を使っています。

**ローカルで中身を変更したHashtableを現在自分がいるルームに送信**しています。

    // ルームのハッシュが送信されたら、送信されたハッシュが入ってくる(Photonの機能で戻り値の型、関数名、引数を一致させると勝手に呼ばれる)
    public void OnPhotonCustomRoomPropertiesChanged(ExitGames.Client.Photon.Hashtable changedRoomHash)
    {
        // 変更されたハッシュを受け取る
        roomHash = changedRoomHash;
    }
最後にOnPhotonCustomRoomPropertiesChanged関数です。

この関数はPhotonが用意している関数でコメントの通り**戻り値の型、関数名、引数**を一致させると呼ばれます。

Unityのスクリプティングランタイムとはまた少し違った仕組みなのですが、見た目上は完全に同じようなものです

呼ばれるタイミングは**ルームに新しくハッシュが送信された時**です。

以下、流れです。
![RoomPropertyのフロー図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/293529/b0caaf80-1e71-a63e-0182-64f435665631.png)

## 諸注意
ルームプロパティは**ルームに設定するプロパティ**なので、**ルームに入ってからセットしないとエラーが出ます。**

またPhotonのターンを制御する機能としてPunTurnManagerがありますが、その制御方法にルームプロパティを使っているので新しく値をルームプロパティに設定しようとするとPunTurnManagerクラスを拡張する必要が出てきます。(これは[公式のリファレンス](https://doc.photonengine.com/ja-jp/pun/v1/demos-and-tutorials/package-demos/rockpaperscissors-demo)にもちょろっと書いてあったと思います)
値を新しく設定する必要があるのであれば独自でターン制御を作ったほうが手っ取り早いかもしれません。

# ラッパークラス
毎回プロパティを使うたびに長い関数を書くのは正直しんどいのでラッパークラスを作ることをおすすめします。

一応例を載せさせていただきます。

```PhotonProperty.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PhotonProperty : MonoBehaviour
{
    // ルームプロパティ用のハッシュ(Dictionary)
    private static ExitGames.Client.Photon.Hashtable roomHash;

    private void Start()
    {
        // ルームプロパティ用のこのプレイヤーのハッシュ(Dictionary)を生成
        roomHash = new ExitGames.Client.Photon.Hashtable();
    }

    // ルームプロパティ ===========================================

    // RoomPropertyが更新された時に呼ばれる
    public void OnPhotonCustomRoomPropertiesChanged(ExitGames.Client.Photon.Hashtable changedRoomHash)
    {
        // 更新したプレイヤーが保持しているハッシュを入れる
        roomHash = changedRoomHash;
    }

    // ルームプロパティのセット -----------------------------------
    // キーが既に存在していたら上書き
    public static void SetRoomProperty<T>(string key, T value)
    {
        roomHash[key] = value;

        // 自身のハッシュをネット上に送信
        PhotonNetwork.room.SetCustomProperties(roomHash);
    }

    // 一次元配列用
    public static void SetRoomPropertyArray<T>(string key, T[] value)
    {
        // 要素数256を超える場合はここをshortなどに変更してください
        for(byte i = 0; i < value.Length; i++)
        {
            roomHash[key + i] = value[i];
        }

        // 自身のハッシュをネット上に送信
        PhotonNetwork.room.SetCustomProperties(roomHash);
    }

    public static void SetRoomPropertyArray<T>(string key, byte arrayNum, T value)
    {
        roomHash[key + arrayNum] = value;

        // 自身のハッシュをネット上に送信
        PhotonNetwork.room.SetCustomProperties(roomHash);
    }

    // キーが既に存在している場合エラーが出る
    public static void SetRoomPropertyAdd<T>(string key, T value)
    {
        roomHash.Add(key, value);

        // 自身のハッシュをネット上に送信
        PhotonNetwork.room.SetCustomProperties(roomHash);
    }

    // ルームプロパティをゲット -----------------------------------
    public static T GetRoomProperty<T>(string key)
    {
        // outを受け取るための変数を用意
        object value;

        // 指定したキーがあれば返す
        if (roomHash.TryGetValue(key, out value))
        {
            // ボックス化解除
            return (T)value;
        }

        // 無かったらnullが返る
        return (T)value;
    }

    // 一次元配列用
    public static T GetRoomPropertyArray<T>(string key, byte arrayNum)
    {
        // outを受け取るための変数を用意
        object value;

        // 指定したキーがあれば返す
        if(roomHash.TryGetValue(key + arrayNum, out value))
        {
            // ボックス化解除
            return (T)value;
        }

        return (T)value;
    }
    // ============================================================
}
```

以下それぞれの関数の使い方をまとめました

```cs
        // 値の設定方法
        // ===============================================================
        // hogeというキーで0をセット
        PhotonProperty.SetRoomProperty("hoge", 0);

        // 一次元配列を作成
        int[] array = { 0, 1, 2, 3 };
        // arrayというキーでarray配列をセット
        PhotonProperty.SetRoomPropertyArray("array", array);
        // ===============================================================

        // 値の取得方法
        // ===============================================================
        // 戻り値の型をint型に指定してキーを入力
        int hoge = PhotonProperty.GetRoomProperty<int>("hoge");

        // 戻り値の型をint型に指定してキーと取得したい要素番号を入力
        int fuga = PhotonProperty.GetRoomPropertyArray<int>("array", 0);
        // ===============================================================
```

良ければお使いください。

# 参考サイト
[【Unity】僕もPhotonを使いたい #11 カスタムプロパティ](https://www.urablog.xyz/entry/2016/09/23/234602)