빠른 시작 가이드: PlayFab Online Subsystem과 PlayFab Unreal Engine Marketplace 플러그인 통합
이 빠른 시작 가이드는 기존 PlayFab Online Subsystem(OSS) 통합 프로젝트에 PlayFab SDK Unreal Engine(UE) Marketplace 플러그인을 통합하는 데 도움이 됩니다. PlayFab SDK 플러그인은 플레이어 인증, 가상 아이템 및 통화 관리, 소셜 기능 생성과 같은 PlayFab 관리자, 클라이언트 및 서버 작업을 수행하는 데 사용됩니다. PlayFab Online Subsystem과 함께 사용하면 프로젝트에서 Unreal Engine 프로젝트용 전체 PlayFab 기능 세트에 액세스할 수 있습니다. PlayFab OSS 또는 PlayFab SDK 플러그인을 서로 독립적으로 사용할 때 첫 번째 단계는 사용자를 인증하는 것입니다. 적절한 설정 없이 동일한 프로젝트에서 둘 다 사용하면 PlayFab OSS와 PlayFab SDK 플러그인이 모두 같은 사용자에 대해 별도의 인증 호출을 수행하게 됩니다. 이 빠른 시작 가이드는 PlayFab OSS를 통해 인증하고 매끄러운 사용자 인증 경험을 위해 PlayFab SDK 플러그인에서 해당 인증을 재사용하는 데 도움이 됩니다.사전 요구 사항
-
<game>.build.cs파일에서 PlayFab OSS를 플러그인으로 통합해야 합니다. 아래 예에서는 통합을 허용하는 토글 옵션을 만들고#ifdef가드를 위한 정의를 설정합니다.// PlayFab OnlineSubsystem Plugin Settings. // // While the PlayFab OSS is integrated with the game at an engine level, we cannot directly access // PF OSS headers unless we integrate it as a plugin. // // `bOSSPlayFabAsPlugin` must be set to true to expose the PlayFab OSS headers directly to the game. bool bOSSPlayFabAsPlugin = false; if (bOSSPlayFabAsPlugin) { PublicDependencyModuleNames.AddRange(new string[] { "OnlineSubsystemPlayFab" }); PublicDefinitions.Add("WITH_OSS_PLAYFAB=1"); } -
<game>.build.cs파일에서 PlayFab SDK 플러그인을 통합해야 합니다. 아래 예에서는 통합을 허용하는 토글 옵션을 만들고#ifdef가드를 위한 정의를 설정합니다.// PlayFab SDK Plugin Settings. // // `bPlayFabPlugin` must be set to true to enable compilation and integration with the PlayFab // SDK Plugin. // Ensure that the PF SDK Plugin is installed via Engine plugin or as a local game plugin. bool bPlayFabPlugin = false; if (bPlayFabPlugin) { PrivateDependencyModuleNames.AddRange(new string[] { "PlayFab", "PlayFabCpp", "PlayFabCommon" }); PublicDefinitions.Add("WITH_PLAYFAB_PLUGIN=1"); } -
<game.build.cs>파일을 업데이트한 후 (및 이후 업데이트할 때마다),.uproject파일을 마우스 오른쪽 버튼으로 클릭하고Generate Visual Studio Project Files를 선택하여 게임의 Visual Studio 프로젝트 파일을 다시 생성해야 합니다. -
PlayFab OSS는 이제 PlayFab OSS 사용자 인증 흐름 완료 시 트리거되는 공용
AuthenticateUserCompletedelegate를 제공합니다. 이 delegate에 바인딩하여 PlayFab OSS 인증의 세부 정보를 검색합니다./** * Delegate used on the completion of FOnlineIdentityPlayFab::AuthenticateUser(). * * @param LocalUserNum the controller number of the associated user that made the request * @param bWasSuccessful true if authentication was successful, false if there was an error * @param PlatformUserIdStr user identifier returned from the service. * @param ErrorStr string representing the error condition */ DECLARE_MULTICAST_DELEGATE_FourParams(FOnAuthenticateUserComplete, int32 /*LocalUserNum*/, bool /*bWasSuccessful*/, const FString& /*PlatformUserIdStr*/, const FString& /*ErrorStr*/); typedef FOnAuthenticateUserComplete::FDelegate FOnAuthenticateUserCompleteDelegate;
단계
전체 코드 예시로 바로 이동할 수도 있습니다.-
올바른 헤더 포함
#ifdef WITH_OSS_PLAYFAB #include "OnlineSubsystemPlayFab.h" #endif // WITH_OSS_PLAYFAB #ifdef WITH_PLAYFAB_PLUGIN #include "PlayFab.h" #include "PlayFabCommon.h" #include "Core/PlayFabClientDataModels.h" #endif // WITH_PLAYFAB_PLUGIN -
PlayFab OSS 검색
FOnlineSubsystemPlayFab* PFOnlineSub = static_cast<FOnlineSubsystemPlayFab*>(IOnlineSubsystem::Get(TEXT("PLAYFAB"))); -
AuthenticateUserCompletedelegate에 바인딩이 delegate에 바인딩되는 함수는 delegate와 동일한 서명을 가져야 합니다. 예를 들어:const FOnlineIdentityPlayFabPtr PlayFabIdentityInterface = PFOnlineSub->GetIdentityInterfacePlayFab(); PlayFabIdentityInterface->AddOnAuthenticateUserCompleteDelegate_Handle ( 0, // LocalUserNum FOnAuthenticateUserCompleteDelegate::CreateUObject(this, &UGameInstance::OnAuthenticateUserComplete) );delegate에 람다를 바인딩할 수도 있습니다. 예를 들어:void UGameInstance::OnAuthenticateUserComplete(int32 localUserNum, bool bWasSuccessful, const FString& platformUserIdStr, const FString& error)// We don't pass the `FOnlineIdentityPlayFabPtr` pointer through the lambda capture since the original // local isn't guaranteed to live longer than the lambda and we want to avoid dangling references. // // You can retrieve `FOnlineIdentityPlayFabPtr` again inside the lambda. PlayFabIdentityInterface->AddOnAuthenticateUserCompleteDelegate_Handle ( 0, // LocalUserNum FOnAuthenticateUserCompleteDelegate::CreateLambda([this](int32 localUserNum, bool bWasSuccessful, const FString& platformUserIdStr, const FString& error) { // lambda execution }); ) -
인증 결과 처리: delegate에 바인딩된 함수에서 인증 결과를 처리합니다. 인증이 성공하면 delegate 트리거에서
platformUserIdStr을 통해 인증된 로컬 사용자를 검색합니다. 그런 다음 PlayFab OSSLocalUser에서 PlayFabLoginResult를 구성합니다.void UGameInstance::OnAuthenticateUserComplete(int32 localUserNum, bool bWasSuccessful, const FString& platformUserIdStr, const FString& error) { if (!bWasSuccessful) { UE_LOG(LogOnlineGame, Error, TEXT("OSS PlayFab AuthenticateLocalUser Failed. Error: %s"), *error); return; } UE_LOG(LogOnlineGame, Display, TEXT("[%s] AuthenticateLocalUser Complete"), ANSI_TO_TCHAR(__FUNCTION__)); FOnlineSubsystemPlayFab* PFOnlineSub = static_cast<FOnlineSubsystemPlayFab*>(IOnlineSubsystem::Get(TEXT("PLAYFAB"))); const FOnlineIdentityPlayFabPtr PlayFabIdentityInterface = PFOnlineSub->GetIdentityInterfacePlayFab(); if (PlayFabIdentityInterface) { if (const auto LocalUser = PlayFabIdentityInterface->GetPartyLocalUserFromPlatformIdString(platformUserIdStr)) { // Setting PlayFab SDK Settings for future API calls auto& PFCommonModule = IPlayFabCommonModuleInterface::Get(); PFCommonModule.SetClientSessionTicket(LocalUser->GetSessionTicket()); PFCommonModule.SetEntityToken(LocalUser->GetEntityToken()); // Create EntityKey auto LocalEntityKey = MakeShared<PlayFab::ClientModels::FEntityKey>(); LocalEntityKey->Id = LocalUser->GetEntityId(); LocalEntityKey->Type = LocalUser->GetEntityType(); // Create EntityToken auto LocalEntityToken = MakeShared<PlayFab::ClientModels::FEntityTokenResponse>(); LocalEntityToken->Entity = LocalEntityKey; LocalEntityToken->EntityToken = LocalUser->GetEntityToken(); // Create LoginResult PlayFab::ClientModels::FLoginResult LoginResult; LoginResult.EntityToken = LocalEntityToken; LoginResult.LastLoginTime = LocalUser->GetEntityTokenUpdateTime(); LoginResult.PlayFabId = LocalUser->GetPlayFabId(); LoginResult.SessionTicket = LocalUser->GetSessionTicket(); // With `LoginResult` populated, we can now use the PlayFab SDK Plugin APIs // however we wish. This state is considered "authenticated". // // This delegate signature functions does not return anything. You can pass `LoginResult` // out of this function however you wish. // // Example psuedocode for a non-existent function that takes `LoginResult` as a parameter: // void UGameInstance::OnAPILoginSuccess(PlayFab::ClientModels::FLoginResult LoginResult); } } } -
PlayFab SDK 플러그인 API 사용:
LoginResult가 채워지면 이제 원하는 대로 PlayFab SDK 플러그인 API를 사용할 수 있습니다. 이 상태는 “인증됨”으로 간주됩니다.
전체 코드 예시
#ifdef WITH_OSS_PLAYFAB
#include "OnlineSubsystemPlayFab.h"
#endif // WITH_OSS_PLAYFAB
#ifdef WITH_PLAYFAB_PLUGIN
#include "PlayFab.h"
#include "PlayFabCommon.h"
#include "Core/PlayFabClientDataModels.h"
#endif // WITH_PLAYFAB_PLUGIN
...
void UGameInstance::Init()
{
Super::Init();
...
// This is an example scenario of integrating the PlayFab OnlineSubsystem with the
// PlayFab SDK Plugin.
//
// In this scenario, you can authenticate via the PlayFab OSS,
// and then re-use that authentication with the PlayFab SDK Plugin.
//
// PF OSS offers a public `AuthenticateUserComplete` delegate that can be bound;
// this delegate triggers on completion of the PF OSS user authentication flow.
//
// Below is an example of a game binding to that delegate, retrieving the
// authenticated local user via the `platformUserIdStr` from the delegate
// trigger, and then constructing a PlayFab `LoginResult` from the PF OSS
// `LocalUser.`
//
// These definitions are defined in `<game>.build.cs`.
#if defined(WITH_OSS_PLAYFAB) && defined(WITH_PLAYFAB_PLUGIN)
// Explicitly retrieve the PlayFab OSS - we can't assume it's the default OSS.
FOnlineSubsystemPlayFab* PFOnlineSub = static_cast<FOnlineSubsystemPlayFab*>(IOnlineSubsystem::Get(TEXT("PLAYFAB")));
UE_LOG(LogOnlineGame, Warning, TEXT("Retrieved PFOnlineSub"));
if (PFOnlineSub)
{
const FOnlineIdentityPlayFabPtr PlayFabIdentityInterface = PFOnlineSub->GetIdentityInterfacePlayFab();
PlayFabIdentityInterface->AddOnAuthenticateUserCompleteDelegate_Handle
(
0, // LocalUserNum
FOnAuthenticateUserCompleteDelegate::CreateUObject(this, &UGameInstance::OnAuthenticateUserComplete)
);
}
else
{
UE_LOG(LogOnlineGame, Error, TEXT("UGameInstance::Init: Unable to find OnlineSubsystemPlayFab"));
}
#endif // WITH_OSS_PLAYFAB && WITH_PLAYFAB_PLUGIN
...
}
void UGameInstance::OnAuthenticateUserComplete(int32 localUserNum, bool bWasSuccessful, const FString& platformUserIdStr, const FString& error)
{
if (!bWasSuccessful)
{
UE_LOG(LogOnlineGame, Error, TEXT("OSS PlayFab AuthenticateLocalUser Failed. Error: %s"), *error);
return;
}
UE_LOG(LogOnlineGame, Display, TEXT("[%s] AuthenticateLocalUser Complete"), ANSI_TO_TCHAR(__FUNCTION__));
FOnlineSubsystemPlayFab* PFOnlineSub = static_cast<FOnlineSubsystemPlayFab*>(IOnlineSubsystem::Get(TEXT("PLAYFAB")));
const FOnlineIdentityPlayFabPtr PlayFabIdentityInterface = PFOnlineSub->GetIdentityInterfacePlayFab();
if (PlayFabIdentityInterface)
{
if (const auto LocalUser = PlayFabIdentityInterface->GetPartyLocalUserFromPlatformIdString(platformUserIdStr))
{
// Setting PlayFab SDK Settings for future API calls
auto& PFCommonModule = IPlayFabCommonModuleInterface::Get();
PFCommonModule.SetClientSessionTicket(LocalUser->GetSessionTicket());
PFCommonModule.SetEntityToken(LocalUser->GetEntityToken());
// Create EntityKey
auto LocalEntityKey = MakeShared<PlayFab::ClientModels::FEntityKey>();
LocalEntityKey->Id = LocalUser->GetEntityId();
LocalEntityKey->Type = LocalUser->GetEntityType();
// Create EntityToken
auto LocalEntityToken = MakeShared<PlayFab::ClientModels::FEntityTokenResponse>();
LocalEntityToken->Entity = LocalEntityKey;
LocalEntityToken->EntityToken = LocalUser->GetEntityToken();
// Create LoginResult
PlayFab::ClientModels::FLoginResult LoginResult;
LoginResult.EntityToken = LocalEntityToken;
LoginResult.LastLoginTime = LocalUser->GetEntityTokenUpdateTime();
LoginResult.PlayFabId = LocalUser->GetPlayFabId();
LoginResult.SessionTicket = LocalUser->GetSessionTicket();
// With `LoginResult` populated, we can now use the PlayFab SDK Plugin APIs
// however we wish. This state is considered "authenticated".
//
// This delegate signature functions does not return anything. You can pass `LoginResult`
// out of this function however you wish.
//
// Example psuedocode for a non-existent function that takes `LoginResult` as a parameter:
// void UGameInstance::OnAPILoginSuccess(PlayFab::ClientModels::FLoginResult LoginResult);
}
}
}
