> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 複数の PlayFab ログインの処理

> 競合する静的状態なしに、単一のクライアントまたはサーバーから複数の同時プレイヤー ログインを管理するために、PlayFab SDK のインスタンス化 API クラスを使用します。

既定では、ほとんどの PlayFab SDK はプレイヤーのログイン結果をキャッシュします。このキャッシュは、単一のプレイヤーのログインを想定する最も一般的なシナリオでは便利です。同時に複数のプレイヤーをサポートするゲームや、プレイヤーの認証情報とサーバーの資格情報の両方を管理するサーバーの場合、そのキャッシュが邪魔になることがあります。こうしたシナリオを容易にするため、PlayFab SDK には静的とインスタンス化された API クラスの両方が用意されています。

## 静的とインスタンス化された API クラス

PlayFab の例やサンプル コードのほとんどは、静的 API クラスを使用して構築されています。たとえば Unity では、**PlayFabClientAPI** への参照が見られるかもしれません。これらの静的クラスは、SDK 内の静的状態に対して読み書きを行います。静的状態への依存により、同じゲーム クライアント内で複数のプレイヤーを扱う場合にこれらのクラスの使用が難しくなります。インスタンス化された API クラスはこれらの問題を回避しますが、その代わりに管理と追跡の要件が増えます。同時に複数の PlayFab ログインをサポートする必要がある場合は、インスタンス化された API クラスを使用することをお勧めします。

Unity SDK では、**PlayFabClientInstanceAPI** が **PlayFabClientAPI** のインスタンス化されたバージョンです。他のすべての API クラスも同様の命名規則に従います。API クラスのインスタンス化されたバージョンを使用する場合、メソッドを呼び出す前にクラスのインスタンスを作成する必要があります。インスタンスを作成するには、いくつかの追加コンテキストを指定する必要があります。ほとんどのクラスでは、追加で必要なコンテキストはプレイヤーの認証コンテキストのみです。Unity では、このコンテキストは **PlayFabAuthenticationContext** です。一部のクラスにはログイン呼び出しが含まれます。これらの呼び出しでは、プレイヤーの認証コンテキストがまだない可能性があります。その場合は、タイトル ID などの基本設定のみを提供します。これらの設定は、**PlayFabApiSettings** オブジェクトを介して渡されます。

## インスタンス化された API クラスの使用

適切な認証コンテキストまたは API 設定オブジェクトでインスタンス化された API クラスを作成したら、静的クラスと同様に使用できます。すべての要求と応答オブジェクトは同じです。唯一の違いは、インスタンスの寿命を追跡し、PlayFab を呼び出す可能性のある人に適切なインスタンスが提供されるようにする責任があなたにあることです。複数のプレイヤーを扱う場合、プレイヤーごとに 1 つずつ、複数の API クラスのインスタンスが必要です。これらのインスタンスは、オーナーとしてプレイヤー オブジェクトの背後にカプセル化するのが最も簡単なことが多いですが、これはあなたに任されています。

プレイヤーをログインさせるインスタンス化されたクラス (**PlayFabClientInstanceAPI** など) は、そのプレイヤーの認証コンテキストを API クラス インスタンス内で作成してキャッシュします。この機能により、必要な追加のクラスを作成するときに認証コンテキストを簡単に参照できます。

## Unity の例

このサンプル コードは、複数のプレイヤーがゲームにログインし、独立した状態が別々のクラス インスタンスで追跡されることを示しています。この例では、API クラスと基本機能が単純化された **PlayFabPlayer** オブジェクトの背後にカプセル化されています。ゲームが開始されると、2 人のプレイヤーをログインさせ、それぞれのプレイヤーについて PlayFab に保存されているデータを取得します。

```csharp theme={null}
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:

```cpp theme={null}
#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:

```cpp theme={null}
#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 クラス インスタンスを作成するために参照できます。


## Related topics

- [PlayFab Unreal GSDK プラグインの概要](/ja-jp/services/playfab/multiplayer/servers/server-sdks/unreal-gsdk/index.md)
- [PlayFab Multiplayer Unity プラグインの概要](/ja-jp/services/playfab/multiplayer/lobby/lobby-matchmaking-sdks/multiplayer-unity-overview.md)
- [サーバー匿名ログイン認証](/ja-jp/services/playfab/identity/player-identity/platform-specific-authentication/anonymous-login.md)
- [Matchmaking SDK quickstart](/ja-jp/services/playfab/multiplayer/matchmaking/quickstart-client-sdk.md)
- [Lobby SDK クイックスタート](/ja-jp/services/playfab/multiplayer/lobby/lobby-getting-started.md)
