> ## 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.

# Integrate the PlayFab Unreal Engine Marketplace plugin

> 기존 PlayFab Online Subsystem 통합 프로젝트에 PlayFab SDK UE Marketplace 플러그인을 통합하는 방법에 대한 지침입니다.

# 빠른 시작 가이드: PlayFab Online Subsystem과 PlayFab Unreal Engine Marketplace 플러그인 통합

이 빠른 시작 가이드는 기존 PlayFab Online Subsystem(OSS) 통합 프로젝트에 [PlayFab SDK Unreal Engine(UE) Marketplace 플러그인](/services/playfab/sdks/unreal)을 통합하는 데 도움이 됩니다.

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` 가드를 위한 정의를 설정합니다.
  ```cs theme={null}
  // 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` 가드를 위한 정의를 설정합니다.
  ```cs theme={null}
  // 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 사용자 인증 흐름 완료 시 트리거되는 공용 `AuthenticateUserComplete` delegate를 제공합니다. 이 delegate에 바인딩하여 PlayFab OSS 인증의 세부 정보를 검색합니다.
  ```cpp theme={null}
  /**
  * 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;
  ```

## 단계

[전체 코드 예시](#full-code-example)로 바로 이동할 수도 있습니다.

1. **올바른 헤더 포함**
   ```cpp theme={null}
   #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
   ```

2. **PlayFab OSS 검색**
   ```cpp theme={null}
   FOnlineSubsystemPlayFab* PFOnlineSub = static_cast<FOnlineSubsystemPlayFab*>(IOnlineSubsystem::Get(TEXT("PLAYFAB")));
   ```

3. **`AuthenticateUserComplete` delegate에 바인딩**

   ```cpp theme={null}
   const FOnlineIdentityPlayFabPtr PlayFabIdentityInterface = PFOnlineSub->GetIdentityInterfacePlayFab();
   PlayFabIdentityInterface->AddOnAuthenticateUserCompleteDelegate_Handle
   (
       0, // LocalUserNum
       FOnAuthenticateUserCompleteDelegate::CreateUObject(this, &UGameInstance::OnAuthenticateUserComplete)
   );
   ```

   이 delegate에 바인딩되는 함수는 delegate와 동일한 서명을 가져야 합니다. 예를 들어:

   ```cpp theme={null}
   void UGameInstance::OnAuthenticateUserComplete(int32 localUserNum, bool bWasSuccessful, const FString& platformUserIdStr, const FString& error)
   ```

   delegate에 람다를 바인딩할 수도 있습니다. 예를 들어:

   ```cpp theme={null}
   // 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
       });
   )
   ```

4. **인증 결과 처리**: delegate에 바인딩된 함수에서 인증 결과를 처리합니다. 인증이 성공하면 delegate 트리거에서 `platformUserIdStr`을 통해 인증된 로컬 사용자를 검색합니다. 그런 다음 PlayFab OSS `LocalUser`에서 PlayFab `LoginResult`를 구성합니다.
   ```cpp theme={null}
   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);
           }
       }
   }
   ```

5. **PlayFab SDK 플러그인 API 사용**: `LoginResult`가 채워지면 이제 원하는 대로 PlayFab SDK 플러그인 API를 사용할 수 있습니다. 이 상태는 “인증됨”으로 간주됩니다.

## 전체 코드 예시

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


## Related topics

- [Unreal Engine 빠른 시작](/ko/services/playfab/sdks/unreal/quickstart.md)
- [Unreal Engine용 PlayFab OnlineSubsystem 릴리스 노트](/ko/services/playfab/multiplayer/networking/unreal-release-notes.md)
- [Unreal Engine와 함께 GDK 사용](/ko/build/gdk-and-engines/unreal/unreal.md)
- [PlayFab for Unreal Engine 개요](/ko/services/playfab/sdks/unified-unreal/overview.md)
- [PlayFab 릴리스 노트 2018](/ko/services/playfab/release-notes/2018.md)
