【Unity初心者】Unityでネットゲームを作りたい【5】PlayFabからプレイヤーデータ(Json)・タイトルデータ(Json)をログイン（新規も）時に取得して配列に設置後、どこでも使えるようにしたい

https://qiita.com/ysyss5500/items/4aeb23639a8cf3d67376

### PlayFabからプレイヤーデータ(Json)・タイトルデータ(Json)をログイン（新規も）時に取得して、配列に設置後、どこでも使えるようにしたい

ホント悩んだ（毎回）
まず、Jsonの形は最初に考えたこの形でおｋ
```
{
  "aaa": [
    {"bbb": "111", "ccc": "222"},
    {"bbb": "333", "ccc": "444"}
  ]
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3979014/d5df38b2-15bc-2077-9157-9c24509a20b5.png)
この形に確定（タイトルデータも

そして、Unityで使える配列にするまでのスクリプト

PlayFabLogin.cs
```
using System;
using System.Collections.Generic;
using PlayFab;
using PlayFab.ClientModels;
using UnityEngine;


/// <summary>
/// PlayFabのログイン処理を行うクラス
/// </summary>
public class PlayFabLogin : MonoBehaviour
{
    private bool _shouldCreateAccount;//アカウントを作成するか    
    private string _customID;//ログイン時に使うID

    //タイトルデータJsonを使えるようにするクラス
    //https://qiita.com/ysyss5500/items/7078965fc5ea6e203d55参照
    [Serializable]
    public class Titoruhairetu
    {
        public Item[] item;
    }
    //これはデータ形式が共通なので使いまわす
    [Serializable]
    public class Item
    {
        public string name;
        public int HP;
        public int ST;
        public int DE;
        public int SP;
        public string Rank;
    }
    //プレイヤーデータのJsonを使えるようにするクラス
    [Serializable]
    public class Pdata
    {
        public Item[] pdata;
    }
    [Serializable]
    public class Pmon
    {
        public Item[] pmon;
    }
//=================================================================================
//ログイン処理
//=================================================================================
public void Start()
    {
        Login();
    }

    /// 新規登録時の初期データ書込み処理
    public static void SetUserData()
    {
        PlayFabClientAPI.UpdateUserData(new UpdateUserDataRequest()
        {
            Data = new Dictionary<string, string>() {
            {"PlayerData","{\"pdata\":[{\"name\":\"あああ\",\"HP\":\"0\",\"ST\":\"0\",\"DE\":\"0\",\"SP\":\"0\",\"Rank\":\"N\"},{\"name\":\"アイテム1\",\"HP\":\"0\",\"ST\":\"0\",\"DE\":\"0\",\"SP\":\"0\",\"Rank\":\"N\"},{\"name\":\"アイテム2\",\"HP\":\"0\",\"ST\":\"0\",\"DE\":\"0\",\"SP\":\"0\",\"Rank\":\"N\"},{\"name\":\"アイテム3\",\"HP\":\"0\",\"ST\":\"0\",\"DE\":\"0\",\"SP\":\"0\",\"Rank\":\"N\"}]}"},
            {"PlayerMons","{\"pmon\":[{\"name\":\"スライム1\",\"HP\":\"1\",\"ST\":\"1\",\"DE\":\"1\",\"SP\":\"1\",\"Rank\":\"N\"},{\"name\":\"スライム2\",\"HP\":\"1\",\"ST\":\"1\",\"DE\":\"1\",\"SP\":\"1\",\"Rank\":\"N\"},{\"name\":\"スライム3\",\"HP\":\"1\",\"ST\":\"1\",\"DE\":\"1\",\"SP\":\"1\",\"Rank\":\"N\"},{\"name\":\"スライム4\",\"HP\":\"1\",\"ST\":\"1\",\"DE\":\"1\",\"SP\":\"1\",\"Rank\":\"N\"},{\"name\":\"スライム5\",\"HP\":\"1\",\"ST\":\"1\",\"DE\":\"1\",\"SP\":\"1\",\"Rank\":\"N\"}]}"}
            }
        },
        result =>
        {
        //なぜか他に書くとaaaを認識しない。なのでここにも書く
            string aaa = "{\"pdata\":[{\"name\":\"あああ\",\"HP\":\"0\",\"ST\":\"0\",\"DE\":\"0\",\"SP\":\"0\",\"Rank\":\"N\"},{\"name\":\"アイテム1\",\"HP\":\"0\",\"ST\":\"0\",\"DE\":\"0\",\"SP\":\"0\",\"Rank\":\"N\"},{\"name\":\"アイテム2\",\"HP\":\"0\",\"ST\":\"0\",\"DE\":\"0\",\"SP\":\"0\",\"Rank\":\"N\"},{\"name\":\"アイテム3\",\"HP\":\"0\",\"ST\":\"0\",\"DE\":\"0\",\"SP\":\"0\",\"Rank\":\"N\"}]}";
            string bbb = "{\"pmon\":[{\"name\":\"スライム1\",\"HP\":\"1\",\"ST\":\"1\",\"DE\":\"1\",\"SP\":\"1\",\"Rank\":\"N\"},{\"name\":\"スライム2\",\"HP\":\"1\",\"ST\":\"1\",\"DE\":\"1\",\"SP\":\"1\",\"Rank\":\"N\"},{\"name\":\"スライム3\",\"HP\":\"1\",\"ST\":\"1\",\"DE\":\"1\",\"SP\":\"1\",\"Rank\":\"N\"},{\"name\":\"スライム4\",\"HP\":\"1\",\"ST\":\"1\",\"DE\":\"1\",\"SP\":\"1\",\"Rank\":\"N\"},{\"name\":\"スライム5\",\"HP\":\"1\",\"ST\":\"1\",\"DE\":\"1\",\"SP\":\"1\",\"Rank\":\"N\"}]}";
    
            Debug.Log("新規データ書き込み成功");
            Pdata playerdata = JsonUtility.FromJson<Pdata>(aaa);
            Debug.Log("なまえ："+ playerdata.pdata[0].name);
            Debug.Log(playerdata.pdata[1].DE);

            Pmon pmondata = JsonUtility.FromJson<Pmon>(bbb);
            Debug.Log(pmondata.pmon[0].name);
            Debug.Log(pmondata.pmon[1].DE);
        },
        error => {
            Debug.Log("エラーです");
            Debug.Log(error.GenerateErrorReport());
        });
    }

    /// 新規ではない場合のデータ読み込み後Jsonを配列に　例（pmondata.pmon[0].name)
    public static void GetUserData()
    {
        var request = new GetUserDataRequest();
        PlayFabClientAPI.GetUserData(request, OnSuccess, OnError);

        void OnSuccess(GetUserDataResult result)
        {
            Debug.Log("GetUserData: Success!");
            Debug.Log(result.Data["PlayerData"].Value);
            Debug.Log(result.Data["PlayerMons"].Value);

            Pdata playerdata = JsonUtility.FromJson<Pdata>(result.Data["PlayerData"].Value);
            Debug.Log(playerdata.pdata[0].name);
            Debug.Log(playerdata.pdata[1].DE);

            Pmon pmondata = JsonUtility.FromJson<Pmon>(result.Data["PlayerMons"].Value);
            Debug.Log(pmondata.pmon[0].name);
            Debug.Log(pmondata.pmon[1].DE);
        }

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

    //タイトルデータ取得して使える配列へ
    public static void GetTitleData()
    {
        var request = new GetTitleDataRequest();
        PlayFabClientAPI.GetTitleData(request, OnSuccess, OnError);

        void OnSuccess(GetTitleDataResult result)
        {
            Debug.Log("GetTitleData: Success!");
            Debug.Log(result.Data["Item"]);
            Titoruhairetu Titoru = JsonUtility.FromJson<Titoruhairetu>(result.Data["Item"]);
            Debug.Log(Titoru.item[0].name);
            Debug.Log(Titoru.item[10].DE);
        }

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

    //ログイン実行
    private void Login()
    {
        _customID = LoadCustomID();
        var request = new LoginWithCustomIDRequest { CustomId = _customID, CreateAccount = _shouldCreateAccount };//補足　既にアカウントが作成されており、CreateAccountがtrueになっていてもエラーにはならない
        PlayFabClientAPI.LoginWithCustomID(request, OnLoginSuccess, OnLoginFailure);
    }

    //ログイン成功
    private void OnLoginSuccess(LoginResult result)
    {
        //アカウントを作成しようとしたのに、IDが既に使われていて、出来なかった場合
        if (_shouldCreateAccount == true && result.NewlyCreated == false)
        {
            Debug.LogWarning("CustomId :" + _customID + "は既に使われています。");
            Login();//ログインしなおし
            return;
        }
        //アカウント新規作成できたらIDを保存
        if (result.NewlyCreated == true)
        {
            SaveCustomID();
            ///ここで新規データ書き込み処理を行う
            SetUserData();
        }
        else
        {
            ///ここで通常ログインでのプレイヤーデータ読み込み処理を行う
            GetUserData();
        }
            Debug.Log("ログイン成功!!");
        GetTitleData();
    }

    //ログイン失敗
    private void OnLoginFailure(PlayFabError error)
    {
        Debug.LogError("PlayFabのログインに失敗\n" + error.GenerateErrorReport());
    }

    //=================================================================================
    //カスタムIDの取得
    //=================================================================================

    //IDを保存する時のKEY
    private static readonly string CUSTOM_ID_SAVE_KEY = "CUSTOM_ID_SAVE_KEY";

    //IDを取得
    private string LoadCustomID()
    {
        //IDをセーブデータから取得
        string id = PlayerPrefs.GetString(CUSTOM_ID_SAVE_KEY);

        //idの中身がnullもしくは空の文字列("")の場合は_shouldCreateAccountはtrueになる。
        _shouldCreateAccount = string.IsNullOrEmpty(id);　//新規にするには、= true; にする
        //_shouldCreateAccount = true;　//通常ログイン時は= string.IsNullOrEmpty(id);

        //idの中身がない場合、文字列を新規作成
        if (_shouldCreateAccount == true)
        {
            return GenerateCustomID();//文字列を新規作成
        }
        else
        {
            return id;//セーブされた文字列を返す
        }
    }

    //IDの保存
    private void SaveCustomID()
    {
        PlayerPrefs.SetString(CUSTOM_ID_SAVE_KEY, _customID);
    }

    //=================================================================================
    //カスタムIDの生成
    //=================================================================================

    //IDを生成する
    //ユニークな文字列をGuidを使用し生成
    //https://docs.microsoft.com/ja-jp/dotnet/api/system.guid.tostring?redirectedfrom=MSDN&view=netframework-4.8#System_Guid_ToString_System_String_
    private string GenerateCustomID()
    {
        //Guidの構造体生成
        Guid guid = Guid.NewGuid();
        return guid.ToString("N");//書式指定子はNを指定　詳細は「Guid.ToString メソッド」のドキュメント参照
    }
}
```
結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3979014/627e2e93-1b21-a9c9-71c1-4df5d10ba4cb.png)
ﾌｳ...やっとここまできました。ただしエラーが消えて動くようになっただけかもだから今後またなおさなきゃだと理解はしてる
でも、どこに書けばエラー出ず動くとなんとなく理解できてきたので楽しい

___
##### 名前を自動で「Player00001」とかで新規だと数字を増やして登録したい
まずタイトルデータにこれを追加
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3979014/0af93234-c88c-2d22-5b36-a43dff37c96f.png)
にしてみたが、タイトルデータは固定データだった気が。。。上書きできん却下

PlayFabに変数を個別に保存できないかな？と調べた
スクリプトを書いてやる方法が出てきた、それも長い...後々やるとして今回却下
ランダムにしよう！でもなるべく重ならないようにしなくては...（重なっちゃダメだろーが）
で
```
 private string _playerNo;//新規の名前設定
```
変数設定
public static void SetUserData()
このままだと中に変数入れられないので
public void SetUserData()
に変更
```
    //PlayerNoを生成する
    private string PlayerNo()
    {
        int idLength = 7;//合計10文字ぐらいにしたいので長さを7に設定
        StringBuilder stringBuilder = new StringBuilder(idLength);
        var random = new System.Random();

        //ランダムに生成
        for (int i = 0; i < idLength; i++)
        {
            stringBuilder.Append(ID_CHARACTERS[random.Next(ID_CHARACTERS.Length)]);
        }

        return stringBuilder.ToString();
    }
```
おなじみ[kan](https://kan-kikuchi.hatenablog.com/entry/PlayFabLogin)さんのところでランダムにIDを生成のがあったので拝借
```
_playerNo = "Py_" + PlayerNo();//新規プレイヤーName作成
```
これで、”Py＿ランダム７文字”という名前を作成して、「あああ」としていたところに入れ替え
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3979014/03441e57-83ce-a133-224c-d08228aaf508.png)
よっしゃー！成功
___
###### 今回までで覚えたこと（C#）
```
private string Aaaa()
{
    a =0;
    return a.ToString();
｝
```

aをToString()で文字列にして、Aaaa()で他で参照できる。returnの使い方も理解できたかな
```
public static void SetUserData()
```
この中に他からの参照（Aaaa（））とかは認識されないのでstaticを取ってやった
これはやっちゃダメなんだろうけど、取らないと名前の変数を認識出来なかった
new とか使うのかな？ｳﾑｩ....
```
PlayFabClientAPI.GetUserData(request, OnSuccess, OnError);
void OnSuccess(GetUserDataResult result)
{
    成功した場合の処理
}

void OnError(PlayFabError error)
{
    失敗した場合の処理
}
```
この形も理解できたかな（なんとなく）

C#の文法もいくつか覚えてきた
やりながら調べながらが私の勉強方法かな
今はネットで調べながらできるから便利ですな
___
###### 他に書いた.csを参照して実行できないの？
ログインのスクリプトが長くなった
んでちょいと考える、初期ログイン以外は、データ更新のたびにプレーヤデータは書き換えなきゃだめだよね、と
タイトルデータはここで保存して使いまわせば良いから、プレーヤデータの読み書きは別のスクリプトに書いて他で参照できないのか？いやできるはず

←前  [【Unity初心者】Unityでネットゲームを作りたい【4】やっぱりログイン時に、新規か判断してプレーヤーデータを読み書きしたい](https://qiita.com/ysyss5500/items/c48335128d115b871276)

[【Unity初心者】Unityでネットゲームを作りたい【6】ゲームの流れを考え直さないとダメだ](https://qiita.com/ysyss5500/items/285cbb1478b1141e4408)　次→

https://qiita.com/ysyss5500/items/4aeb23639a8cf3d67376