UnityのPlayFabを使ってEメールログインを作るときのTips

# 使用バージョン
PlayFabSDK: 2.110.210628
Unity: 2020.3.1f1

# この記事で話さないこと
PlayFabそもそもの導入方法など

# この記事で話すこと
PlayFabでEmailのログインを実装するときの注意点やテストする際のTipsを実例で紹介

# はじめに
私はPlayFabを使って現在ゲームを作っているエンジニアです
PlayFabはユーザの登録やログインなど、便利な機能が多く、無料で使える枠も多いので、採用しています
しかし、今回ユーザのログインにEmailを使ったものを実装した際に、少し詰まった。というより不便な部分があったので、
そこを回避するためのTipsをご紹介します

# PlayFabのEmailを使ったログインの実装
基本的に以下の実装をするだけでユーザの登録ができます

```
using PlayFab;
using PlayFab.ClientModels;
using UnityEngine;

public class EmailLoginTest : MonoBehaviour
{
    private string userName = "yamada1";
    private string password = "password";
    private string email = "aiueo@email.com";
    // Start is called before the first frame update
    void Start()
    {
        var RegisterData = new RegisterPlayFabUserRequest()
        {
            Username = userName,
            Email = email,
            Password = password
        };

        PlayFabClientAPI.RegisterPlayFabUser(RegisterData, result =>
        {
            Debug.Log("Congratulations, you made your PlayFab account!");
        }, error => Debug.Log(error.GenerateErrorReport()));
    }
}
```

こちらで作成したユーザでログインするにはこのように実装します

```
void Login()
    {
        GetPlayerCombinedInfoRequestParams InfoRequestParams = new GetPlayerCombinedInfoRequestParams
        {
            GetUserAccountInfo = true // 設定したUsernameを取れる設定にしておく
        };
        // 設定したメールとパスワードでログインを試みる
        var request = new LoginWithEmailAddressRequest{Email = email,Password = password};
        request.InfoRequestParameters = InfoRequestParams;
        PlayFabClientAPI.LoginWithEmailAddress(request, result =>
        {
            // ログイン成功したらログを出す
            Debug.Log("WelcomeBack:" + result.InfoResultPayload.AccountInfo.Username);
        }, error => {});
    }
```

これをユーザ生成後に実行することで、以下の結果を得られます
![WelcomeBack.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49946/4f1cd461-1922-a25b-cd0a-5b74a00f8a23.png)

とても簡単ですね。しかし、このEmailログインはいくつかの問題があります。その内容と対策を紹介します

# 問題となった部分
## 1.ユーザ名が英数字のみで3文字以上が必要
例として、ユーザの登録を以下のようにしてみます

```
    private string userName = "やまだ";
    private string password = "password";
    private string email = "aiueo@email.com";
```
このようにした上で、先ほどのログインの処理を実行すると、失敗してユーザ登録ができなくなります
![invalid.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49946/30d2b360-6730-2106-0cc2-a8b14b51b79c.png)
これは、userNameがマルチバイト文字になっているため、登録ができないというエラーです
日本でアプリを出す際に、userNameに日本語が使えないのは不便ですね
しかも、登録にはUsernameの指定が必須になっていますので、そのデータをプレイヤーの名前として使う場合は不便となりました

## 2.ユーザ名、Emailの重複が不可
さらに、最初のuserNameである`yamada1`に戻した上でもう一度ユーザ生成をしてみます

![notavailable.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49946/870289c9-9eb5-17e7-2325-33d6604ff42c.png)
先ほど通ったはずなのに、今回はエラーがでてしまいました
実は、PlayFabでのUsernameとemailはすでに登録されているものと同じものは使えません
Emailはともかく、Usernameが同じものが使えないものは不便です

## 3.テストがとてもしづらい
UsernameやEmailが重複できないとなると、リリース後も大変だと思いますが、開発段階のテストも面倒となります
毎回違ったものを入力しなくてはいけないのは開発の効率に影響が出るレベルです

# 解決案
今作成しているゲームでは、以上の３つの問題を解決するために、以下の実装を行いました

## 1.ユーザ名はランダム生成にし、表示するようなユーザ名は別に入力する
ユーザ名の重複を防ぐために、以下のようなコードに変更しました

```
        var RegisterData = new RegisterPlayFabUserRequest()
        {
            Username = Guid.NewGuid().ToString().Replace("-", "").Substring(0, 20),
            Email = email,
            Password = password
        };
```
このコードでは、必須となり重複が不可能なUsernameに対して、GUIDを用いています
また、長さは20文字までで、ハイフンは使えないので、ハイフンを除いた先頭20文字を使っています

## 2.テストようにランダムな入力のデバッグボタンを作成
これは開発中の画面ですが、以下のようなボタンを用意しています
![ランダム入力サンプル.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/49946/19c7aa23-6528-be09-6f1d-4d150e2ea57e.png)
この「ランダム入力」ボタンを押すことで、名前とEmailをランダムに入力し、パスワードを`password`と固定で入力できるようにしました
Emailについては、`@`の前に`+12345`のようにすることで、同じアドレスでも別のアドレスのようにすることができますが、
今回はユーザ登録時にメールを飛ばす機能は未実装なため、ランダムに入力できるようにしています。
ここの実装は以下のようになっています

```
        // デフォルトでちゃんと非アクティブになるようにしておく
        randomCreateButton.gameObject.SetActive(false);
        #if DEBUG // DEBUGビルド以外では処理は入らないようにする
        randomCreateButton.gameObject.SetActive(true);
        randomCreateButton.onClick.AddListener(() =>
        {
            // 英数字のリストを持っておく
            var characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
            var resultString = "";
            // 処理はデバッグようなのである程度適当に。重複しなければ良い
            for (int i = 0; i < 8; i++)
            {
                resultString += characters[Random.Range(0, characters.Length)];
            }

            // メールアドレスのフォーマットは必要なので、最後にドメインをつける
            resultString += "@gmail.com";
            email.text = resultString;
            // パスワードはpasswordで固定
            password.text = "password";
            // 名前は3文字以上９文字未満にする
            var nameLength = Random.Range(3, 9);
            for (int i = 0; i < nameLength; i++)
            {
                // TextMeshProに登録されている文字からランダムに選ぶ
                var rnd = Random.Range(0, name.fontAsset.characterTable.Count);
                name.text += "" + Convert.ToChar(name.fontAsset.characterTable[rnd].unicode);
            }
        });
        #endif
```

拙いコードではありますが、デバッグようの処理なのでパフォーマンスなどは考えていません
これにより、Emailログインに必要なユーザ名とEmailをテストしやすく、重複が無いように実装しています

## ユーザ名はどうやっているの？
ここまででユーザ登録は実装できました
しかし、先ほどの画像で入力したユーザ名が出ていない。という問題があります
ここは、ユーザ名はユーザ生成後に、PlayFabのタイトルデータという機能に登録しています
詳しい説明は`PlayFab タイトルデータ`と検索すれば、詳しく丁寧に解説している記事やブログがいっぱいありますので、ここでは省略しますが、
今回登録直後のデータの例はこのようになっています(先ほどのランダムのデータは登録ボタン押し忘れたので再実行しました)

```
{
  "id": "",
  "pinballData": "",
  "userName": "倖髀侭"
}
```
ようは、日本語で登録されたデータをPlayFabのUsernameではなく、独自のデータとして持ってしまおう。という魂胆です
こちらはゲームごとに自由に設定できるデータなので、重複も文字数も何も関係なく作れます

## 最後に
PlayFabを使うと、Emailでのログイン以外にも様々なログインが簡単に実装できます
使っていて不便に思うようなところも、工夫をすればなんとかなることも多いので、
ちょっとでも気になった方がいたら是非お試しすることをオススメいたします