simplestarの技術ブログ

目的を書いて、思想と試行、結果と考察、そして具体的な手段を記録します。

PlayFab:ログインタイミングを気にせずプログラミングする術

最初にひらめいたのはアクションをキューイングすればいいんだよ!の一言

言葉をプログラムに書き下すと次の通り
ちゃんと期待通り動いた

前の記事
simplestar-tech.hatenablog.com

の TitleData を取得する関数の処理、コールバックで成功を返すつくりなので、このように改造が自由

    /// <summary>
    /// タイトルデータを取得
    /// </summary>
    /// <typeparam name="T">取得したいデータのクラスを指定</typeparam>
    /// <param name="callback">取得成功時の処理</param>
    public static void GetTitleData<T>(UnityAction<T[]> callback)
    {
        PlayFabLogin.AfterLoginCall(() =>
        {
            PlayFabClientAPI.GetTitleData(new GetTitleDataRequest { }, result =>
            {
                var type = typeof(T);
                var titleData = JsonSerializer.Deserialize<T[]>(result.Data[type.Name]);
                callback?.Invoke(titleData);
            },
                error => { Debug.LogError($"GetTitleData: Fail...{error.GenerateErrorReport()}"); });
        });
    }

からくりは次のようにして実装しました。

using PlayFab;
using PlayFab.ClientModels;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

/// <summary>
/// PlayFab のログインをゲーム開始時に試行し、ログイン前に呼ばれた API 処理を処理
/// </summary>
public class PlayFabLogin : MonoBehaviour
{
    /// <summary>
    /// 引数アクションをログインしてから実行する
    /// </summary>
    /// <param name="action"></param>
    public static void AfterLoginCall(UnityAction action)
    {
        if (isPlayFabLogin)
        {
            // もうログインしてるんだからそのまま実行
            action?.Invoke();
        }
        else
        {
            // まだログインしてないのでキューイング
            actionQueue.Enqueue(action);
        }
    }

    void Start()
    {
        // タイトルIDをメタデータから取得
        if (string.IsNullOrEmpty(PlayFabSettings.TitleId))
        {
            Debug.LogError("PlayFab TitleId is Empty!");
            return;
        }
        // ログインを試行
        var request = new LoginWithCustomIDRequest { CustomId = "GettingStartedGuide", CreateAccount = true };
        PlayFabClientAPI.LoginWithCustomID(request, OnLoginSuccess, OnLoginFailure);
    }

    /// <summary>
    /// ログイン成功
    /// </summary>
    /// <param name="result">EntityTokenなど</param>
    void OnLoginSuccess(LoginResult result)
    {
        Debug.Log("PlayFab ready to call API");
        // キューにあるタスクを順に実行
        while (0 < actionQueue.Count)
        {
            var action = actionQueue.Dequeue();
            action?.Invoke();
        }
        // ログインしたフラグ変更
        isPlayFabLogin = true;
    }

    /// <summary>
    /// 何らかの理由でログインに失敗
    /// </summary>
    /// <param name="error">エラー情報</param>
    void OnLoginFailure(PlayFabError error)
    {
        Debug.LogWarning("Something went wrong with PlayFab API call.");
        Debug.LogError($"Here's some debug information: {error.GenerateErrorReport()}");
        // ログインせずゲーム続けると、どんどんキューに詰められてスタックオーバーフローするかもね
    }

    /// <summary>
    /// ゲーム開始時にログインするが、もしもその前に API コールがあったらこのキューに関数が詰められる
    /// </summary>
    static Queue<UnityAction> actionQueue = new Queue<UnityAction>();
    /// <summary>
    /// PlayFab のタイトルログインに成功したら true に変わる
    /// </summary>
    static bool isPlayFabLogin = false;
}

同じように、ログインタイミング気にしてログインしたか確認して~とかいう依存コード書く前に、参考にどうぞ