既定では、ほとんどの PlayFab SDK はプレイヤーのログイン結果をキャッシュします。 このキャッシュは、シングル プレイヤー ログインで予想される最も一般的なシナリオで役立つ可能性があります。 複数のプレイヤーの同時アクセスをサポートするゲームや、プレイヤーの認証マテリアルとサーバーの資格情報の両方を管理するサーバーでは、そのキャッシュが邪魔になる可能性があります。 これらのシナリオを容易にするために、PlayFab SDK には静的 API クラスとインスタンス化された API クラスの両方が含まれています。
静的 API クラスとインスタンス化された API クラス
PlayFab のほとんどの例とサンプル コードは、静的 API クラスを使用して構築されています。 たとえば、Unity では PlayFabClientAPI へのリファレンスが表示される場合があります。 これらの静的クラスは、SDK 内の静的な状態への書き込みと読み取りを行います。 静的な状態に依存しているため、同一のゲーム クライアント内で複数のプレイヤーを扱う場合、これらのクラスを使用するのが困難になります。 インスタンス化された API クラスは、パーツの管理や追跡の要件の増加と引き換えに、これらの問題を回避します。 複数の PlayFab ログインを同時にサポートする必要がある場合には、インスタンス化された API クラスの使用をお勧めします。
Unity SDK では、PlayFabClientInstanceAPI は PlayFabClientAPI のインスタンス化されたバージョンです。 その他すべての API クラスは、同様の名前付けパターンに従っています。 API クラスのインスタンス化されたバージョンを使用する場合には、任意のメソッドを呼び出す前にクラスのインスタンスを作成する必要があります。 インスタンスを作成するには、追加のコンテキストを指定する必要があります。 ほとんどのクラスでは、追加の必須コンテキストはプレイヤーの認証コンテキストにすぎません。 Unity では、このコンテキストは PlayFabAuthenticationContext です。 一部のクラスにはログイン呼び出しが含まれています。 これらの呼び出しには、プレイヤーの認証コンテキストがまだない可能性があります。 その場合には、タイトル ID などの基本的な設定のみを指定する必要があります。 これらの設定は、PlayFabApiSettings オブジェクトを介して渡されます。
インスタンス化された API クラスの使用
適切な認証コンテキストまたは API 設定オブジェクトを使用してインスタンス化された API クラスを作成すれば、静的クラスと同様に使用できるようになります。 要求と応答のオブジェクトはすべて同じものです。 唯一の違いは、インスタンスの有効期間を追跡し、PlayFab の潜在的な呼び出し元に適切なインスタンスが提供されるようにする責任があるという点です。 複数のプレイヤーを扱う場合には、任意の API クラスの複数のインスタンス (プレイヤーごとに 1 つ) が必要です。 多くの場合、プレイヤー オブジェクトの背後でカプセル化されたこれらのインスタンスを所有者として管理するのが最も簡単な方法ですが、その選択はユーザーに委ねられています。
プレイヤーをログインさせるインスタンス化されたクラス (PlayFabClientInstanceAPI など) も、API クラスのインスタンス内でそのプレイヤーの認証コンテキストを作成してキャッシュします。 この機能を使用することで、必要なクラスを作成する際に認証コンテキストを簡単に参照できるようになります。
Unity の例
このサンプル コードでは、複数のプレイヤーがゲームにログインし、個別のクラス インスタンスで独立した状態を追跡する方法を示しています。 この例では、API クラスと基本的な機能が、シンプルな PlayFabPlayer オブジェクトの背後でカプセル化されています。 ゲームが開始されると 2 人のプレイヤーをログインさせ、それらのプレイヤーそれぞれについて PlayFab に保存されているデータを取得します。
using PlayFab;
using PlayFab.ClientModels;
using PlayFab.DataModels;
using System.Collections.Generic;
using UnityEngine;
public class PlayFabLogin : MonoBehaviour
{
PlayFabPlayer player1 = new PlayFabPlayer();
PlayFabPlayer player2 = new PlayFabPlayer();
// Start is called before the first frame update
void Start()
{
if (string.IsNullOrEmpty(PlayFabSettings.staticSettings.TitleId))
{
// Please change the titleId below to your own titleId from PlayFab Game Manager.
PlayFabSettings.staticSettings.TitleId = "";
}
player1.Login("testLogin1");
player2.Login("testLogin2");
}
// Update is called once per frame
void Update()
{
if (player1.loggedIn && !player1.dataLoaded && !player1.dataLoading)
{
player1.LoadData();
}
if (player2.loggedIn && !player2.dataLoaded && !player2.dataLoading)
{
player2.LoadData();
}
}
}
class PlayFabPlayer
{
public bool loggedIn = false;
public bool dataLoading = false;
public bool dataLoaded = false;
public string PlayFabId;
public Dictionary<string, ObjectResult> playerData;
private PlayFabClientInstanceAPI clientApi;
private PlayFabDataInstanceAPI dataApi;
public void Login(string customId)
{
clientApi = new PlayFabClientInstanceAPI(PlayFabSettings.staticSettings);
var request = new LoginWithCustomIDRequest { CustomId = customId, CreateAccount = true };
clientApi.LoginWithCustomID(request, result =>
{
PlayFabId = result.PlayFabId;
loggedIn = true;
dataApi = new PlayFabDataInstanceAPI(clientApi.authenticationContext);
Debug.Log("Login call succeeded.");
}, error =>
{
Debug.LogWarning("Something went wrong with the login call.");
Debug.LogError("Here's some debug information:");
Debug.LogError(error.GenerateErrorReport());
});
}
public void LoadData()
{
dataLoading = true;
var request = new GetObjectsRequest { Entity = new PlayFab.DataModels.EntityKey { Id = clientApi.authenticationContext.EntityId, Type = clientApi.authenticationContext.EntityType } };
dataApi.GetObjects(request, result =>
{
playerData = result.Objects;
dataLoaded = true;
dataLoading = false;
Debug.Log("Player data loaded.");
}, error =>
{
Debug.LogWarning("Something went wrong with the GetObjects call.");
Debug.LogError("Here's some debug information:");
Debug.LogError(error.GenerateErrorReport());
});
}
}
Unreal の例
このコード サンプルでは、独自の PlayFab ログイン コンテキストを含む Unreal のアクターを示しています。 ALoginActor クラス内で PlayFab API インスタンス クラスをカプセル化する方法を示しています。 複数の ALoginActor インスタンスは、独自の CustomId を指定してマップに追加され、PlayFab の操作を個別に実行します。
LoginActor.h:
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "PlayFab.h"
#include "Core/PlayFabError.h"
#include "Core/PlayFabClientDataModels.h"
#include "Core/PlayFabClientAPI.h"
#include "Core/PlayFabDataAPI.h"
#include "LoginActor.generated.h"
UCLASS()
class MINUE_PF_MARKET_API ALoginActor : public AActor
{
GENERATED_BODY()
public:
// Sets default values for this actor's properties
ALoginActor();
// Please change the TitleId below to your own TitleId from PlayFab Game Manager.
UPROPERTY(EditAnywhere, config, Category = Settings)
FString TitleId = TEXT("");
UPROPERTY(EditAnywhere, config, Category = Settings)
FString CustomId = TEXT("ExampleCustomId");
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
void OnLoginSuccess(const PlayFab::ClientModels::FLoginResult& Result);
void OnGetObjectsSuccess(const PlayFab::DataModels::FGetObjectsResponse& Result);
void OnError(const PlayFab::FPlayFabCppError& ErrorResult) const;
public:
bool LoggedIn = false;
// Called every frame
virtual void Tick(float DeltaTime) override;
PlayFabClientPtr clientAPI = nullptr;
PlayFabDataPtr dataAPI = nullptr;
TMap<FString, PlayFab::DataModels::FObjectResult> PlayerData;
bool DataLoaded = false;
};
LoginActor.cpp:
#include "LoginActor.h"
ALoginActor::ALoginActor()
{
// Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
void ALoginActor::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
}
void ALoginActor::BeginPlay()
{
Super::BeginPlay();
GetMutableDefault<UPlayFabRuntimeSettings>()->TitleId = TitleId;
clientAPI = IPlayFabModuleInterface::Get().GetClientAPI();
dataAPI = IPlayFabModuleInterface::Get().GetDataAPI();
PlayFab::ClientModels::FLoginWithCustomIDRequest request;
request.CustomId = CustomId;
request.CreateAccount = true;
clientAPI->LoginWithCustomID(request,
PlayFab::UPlayFabClientAPI::FLoginWithCustomIDDelegate::CreateUObject(this, &ALoginActor::OnLoginSuccess),
PlayFab::FPlayFabErrorDelegate::CreateUObject(this, &ALoginActor::OnError)
);
}
void ALoginActor::OnLoginSuccess(const PlayFab::ClientModels::FLoginResult& Result)
{
UE_LOG(LogTemp, Log, TEXT("Login call succeeded."));
LoggedIn = true;
PlayFab::DataModels::FGetObjectsRequest dataRequest;
dataRequest.AuthenticationContext = Result.AuthenticationContext;
dataRequest.Entity.Id = Result.EntityToken->Entity->Id;
dataRequest.Entity.Type = Result.EntityToken->Entity->Type;
dataAPI->GetObjects(
dataRequest,
PlayFab::UPlayFabDataAPI::FGetObjectsDelegate::CreateUObject(this, &ALoginActor::OnGetObjectsSuccess),
PlayFab::FPlayFabErrorDelegate::CreateUObject(this, &ALoginActor::OnError)
);
}
void ALoginActor::OnError(const PlayFab::FPlayFabCppError& ErrorResult) const
{
UE_LOG(LogTemp, Error, TEXT("Something went wrong with your API call.\nHere's some debug information:\n%s"), *ErrorResult.GenerateErrorReport());
}
void ALoginActor::OnGetObjectsSuccess(const PlayFab::DataModels::FGetObjectsResponse& Result)
{
PlayerData = Result.Objects;
DataLoaded = true;
UE_LOG(LogTemp, Log, TEXT("Player data loaded."));
}
サーバー認証
インスタンス化された API クラスを使用してゲーム クライアントが複数のプレイヤーを処理できるようにする方法と同様に、これらのインスタンスによってサーバーはタイトルとプレイヤー認証の組み合わせまたは複数のタイトルを同時に処理できるようになります。 基本的なパターンはほぼ同じです。 サーバー ログインを処理する API クラスをインスタンス化し、そのインスタンスに適切な PlayFabApiSettings オブジェクトを指定してから、認証 API を呼び出します。 サーバー上にいる場合、その API は通常 PlayFabAuthenticationInstanceAPI.GetEntityToken です。 プレイヤーのログインと同様に、GetEntityToken 呼び出しの結果は API クラス インスタンスにキャッシュされ、authenticationContext インスタンス プロパティを介してさらに多くの API クラス インスタンスを作成するために参照することができます。