UnityからPlayFabのユーザーデータをCRUDする

今回は Unity から PlayFab のユーザーデータを CRUD してみます。
※PlayFabとは？という方は [こちら](https://qiita.com/_y_minami/items/6baa0445c2b161aeec65) をご覧ください。

## まえがき

### 1. ユーザーデータとは
スマホアプリの RPG を想像してみてください。
以下のようなデータがユーザーに紐付いていますよね。

- プレイヤー名
- レベル
- 経験値
- ジョブ
- デッキ

こうしたデータをユーザーデータとして PlayFab の KVS で管理します。

### 2. ユーザーデータの例外について
よくゲームをプレイされる方は先程の例を見て、`インベントリや魔法石とかは対象じゃないの？` と思われたかもしれません。

PlayFab はユーザーデータ以外にもデータを管理する機能が複数存在します。
例えば下記のデータについてはそれぞれ専用の管理機能が提供されているのでそちらを使用します。

- キャラクター
- インベントリ
- 通貨
- フレンド
- ファイル

この記事ではこれらの管理はスコープ外とします。

### 3. ユーザーデータとプレイヤーデータとキャラクターデータ

PlayFab は `ユーザーデータ` を `プレイヤーデータ` と表記することもあります。
実際に GameManager（PlayFabのWebの管理画面）と API や SDK では違う名前が使われています。

- GameManager -> PlayerData
- APIやSDK -> UserData

この2つは同じものを示していますので慣れるまで注意してください。

また、 `キャラクターデータ` という言葉が出てきた場合はユーザーが保持している `キャラクターのデータ` を示しています。
これはユーザーデータとは別物ですのでこちらも注意してください。

ここまでが前書きです。長くてすいません。

## ユーザーデータを Unity から CRUD する

### 1. 下準備（Unity から PlayFab SDK を使う準備と PlayFab へのログインの実装）
@ume67026265 さんが PlayFab のアカウントの作り方と、Unity へ SDK を導入する記事を書かれています。
不慣れな方はこちらを参考に進めるとスムーズに準備ができると思います。

- [PlayFab始めました](https://qiita.com/ume67026265/items/380e7068e9a2b60b26bc) ※アカウントの作り方
- [PlayFabでUnityを動かしてみる -その1下準備編-](https://qiita.com/ume67026265/items/c89b391e36855f45586f) ※Unity へ PlayFab SDK を導入する手順
- [PlayFabでUnityを動かしてみる -その2 APIコールを作ってみる-](https://qiita.com/ume67026265/items/b9313c696ceaa301baa8) ※ユーザーを PlayFab へログインさせるための手順

### 2. Create
準備が終わったらユーザーデータを Create しましょう。
と言いたいところですが、実は 1. の下準備の中でユーザーがログインした時点でユーザーデータは PlayFab 上に自動的に Create されています。

GameManager でユーザーデータが作成されたことを確認しましょう。

左メニューの「プレイヤー」を開くと、先程ログインしたプレイヤーの情報が表示されるので ID の部分をクリックします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/97193/ace7b091-fe2e-44df-2af5-c64185e64854.png)

プレイヤーデータ（タイトル）を開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/97193/bf330789-3052-9554-03b3-7ff288b9b766.png)

中身は空ですが、ユーザーデータが作成されていることが確認できました。
次は Read を試したいので、適当な Name を登録しておきましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/97193/4bcc3a07-5e2f-b02d-3705-a3d91f7254ff.png)

### 3. Read
先程登録した Name を取得して Unity で表示してみましょう。

下準備で作った PlayFabLogin という Script を編集します。
ログインに成功したらユーザーデータを取得して名前を表示するようにしてみます。

#### 3.1 PlayFabLogin クラスに以下のメソッドを追加
``` C#
    public static void GetUserData()
    {
        var request = new GetUserDataRequest();
        PlayFabClientAPI.GetUserData(request, OnSuccess, OnError);

        void OnSuccess(GetUserDataResult result)
        {
            Debug.Log("GetUserData: Success!");
            Debug.Log($"My name is {result.Data["Name"].Value}");
        }

        void OnError(PlayFabError error)
        {
            Debug.Log("GetUserData: Fail...");
            Debug.Log(error.GenerateErrorReport());
        }
    }
```

#### 3.2 OnLoginSuccess メソッドの中で GetUserData を呼び出す
``` C#
    private void OnLoginSuccess(LoginResult result)
    {
        Debug.Log("Congratulations, you made your first successful API call!");

        GetUserData(); // ここを追加
    }
```

これで Unity を再生してみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/97193/516cc770-832c-9635-762e-b5071a6f8579.png)
名前が表示できました。

### 4. Update
次は Name を変更してみましょう。
先程と同じ要領で Update のメソッドを追加します。

#### 4.1 PlayFabLogin クラスに以下のメソッドを追加
``` C#
    public static void UpdateUserData()
    {
        var request = new UpdateUserDataRequest()
        {
            Data = new Dictionary<string, string>
            {
                { "Name", "Kita" }
            }
        };

        PlayFabClientAPI.UpdateUserData(request, OnSuccess, OnError);

        void OnSuccess(UpdateUserDataResult result)
        {
            Debug.Log("UpdateUserData: Success!");
            GetUserData();
        }

        void OnError(PlayFabError error)
        {
            Debug.Log("UpdateUserData: Fail...");
            Debug.Log(error.GenerateErrorReport());
        }
    }
```

#### 4.2 OnLoginSuccess メソッドの中で UpdateUserData を呼び出す
``` C#
    private void OnLoginSuccess(LoginResult result)
    {
        Debug.Log("Congratulations, you made your first successful API call!");

        GetUserData();

        UpdateUserData(); // ここを追加
    }
```

これで Unity を再生してみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/97193/927cabe3-6605-b03b-a590-8ca7ce53c304.png)
名前が変わりました。

ちなみに新しい Key を追加する場合は Data の Dictionary をそのようにしてあげれば動きます。

``` C#
    Data = new Dictionary<string, string>
    {
        { "Name", "Minami" },
        { "Job", "TeaAdvisor" }  // Job を新しく追加してみる
    }
```
Job が追加されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/97193/58819d7e-4ab6-5f34-4dbc-b7b048faeaea.png)


なお Key を削除する場合は Value を null にします。

``` C#
    Data = new Dictionary<string, string>
    {
        { "Name", "Minami" },
        { "Job", null}  // Job はなかったことに
    }
```
Job が消えましたね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/97193/37094a81-edd3-16cd-6203-584074ea2ba1.png)

### 5. Delete
CRUD するというタイトルにしたものの、ユーザーデータをまるごと削除する操作はありませんでした。

Update の項目に書いた方法ですべての Key を削除するか、ユーザーそのものを削除するしか方法は無いようです。

ユーザーデータを良い感じに初期化してくれるファンクションでも作っておくと捗るかもしれないですね。

## あとがき
一度試してみたら簡単に使える感じだと思いますので、興味がある方は是非試してみてください。

ちなみにユーザーデータは下記の3種類が存在します。
- UserData（Clientから読み書き可能なもの）
- UserReadOnlyData（Clientからは読み取りしかできないもの）
- UserInternalData（Clientからは読み書きできないもの）

チートされたりしないように適切なものを使いましょう。

## 参考/関連
- [ユーザーデータに関するドキュメント](https://docs.microsoft.com/ja-jp/gaming/playfab/features/data/playerdata/quickstart)
- [指定した Key を削除する方法について書かれたフォーラムのやりとり](https://community.playfab.com/questions/54/205459448-Remove-Player-Data-based-on-Keys.html)
- [UnityでPlayFabのタイトルデータを取得して表示する](https://qiita.com/_y_minami/items/3396f832d868d52bbbaf)