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

# XBOX Live helper library for PlayFab Party

> PartyXboxLive 헬퍼 라이브러리를 사용하여 XBOX Live ID, 채팅 권한 및 개인 정보 보호 설정을 PlayFab Party 음성 및 네트워킹과 연결합니다.

# XBOX Live Helper 라이브러리 개요

PlayFab Party용 XBOX Live Helper 라이브러리는 PlayFab Party를 사용하는 게임이 통신과 관련된 [XBOX Live 정책](https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/live/get-started/live-xbl-overview)(XR-015 및 XR-045)을 충족하도록 돕도록 설계되었습니다. XBOX Live Helper 라이브러리는 [Nuget.org](https://www.nuget.org/profiles/PlayFab)에서 사용할 수 있습니다.

## PlayFab Party 라이브러리와의 호환성

API에서 호환성이 손상되는 변경을 최소화하기 위해 노력하지만, PlayFab Party API에 대한 일부 변경 사항으로 인해 XBOX Live Helper 라이브러리가 잘못된 값을 반환할 수 있습니다. 라이브러리 버전이 호환되는지 확인하려면 아래 표를 참조하세요.

| XBOX Live Helper 라이브러리 <br /> 버전 | PlayFab Party 버전 <br /> 1.0.1 | PlayFab Party 버전 <br /> 1.3.0+ |
| -------------------------------- | :---------------------------: | :----------------------------: |
| **1.0.1**                        |               ✔               |                                |
| **1.1.0**                        |               ✔               |                                |
| **1.2.0**                        |                               |                ✔               |
| **1.2.5**                        |                               |                ✔               |

## XBOX Live 사용자 추적

PlayFab Party XBOX Live Helper 라이브러리는 현재 Party 세션에 참여하는 XBOX Live 사용자에 대해 명시적으로 알림을 받아야 합니다. 타이틀은 [multiplayer session document](https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/live/get-started/live-xbl-overview)에 대한 변경 사항을 수신하고 `PartyXblManager::CreateLocalChatUser` 및 `PartyXblManager::CreateRemoteChatUser`를 통해 XBOX Live Helper 라이브러리에 해당 명단을 반영하여 라이브러리에 알리는 것이 권장됩니다.

로컬 사용자의 경우:

```cpp theme={null}
void
OnLocalXboxUserAddedToMPSD(
    uint64_t xboxUserId
    )
{
    PartyXblLocalChatUser* localChatUser;
    PartyError err = PartyXblManager::GetSingleton().CreateLocalChatUser(xboxUserId, nullptr, &localChatUser);
    if (PARTY_FAILED(err))
    {
        DEBUGLOG("CreateLocalChatUser failed: %s\n", PartyXblManager::GetErrorMessage(err));
        return;
    }
}
```

이 시점에서 해당 로컬 XBOX 사용자에 대해 PartyLocalChatControl이 이미 존재하는 경우, SetCustomContext 메서드를 통해 이 PartyXblLocalChatUser와 연결할 수 있습니다.

```cpp theme={null}
    localChatControl->SetCustomContext(localChatUser);
    localChatUser->SetCustomContext(localChatControl);
```

그렇지 않은 경우 이 새 PartyXblLocalChatUser를 사용하여 채팅 컨트롤을 생성하고 그때 연결할 수 있습니다. 자세한 내용은 [PartyXblLocalChatUsers에서 PartyLocalChatControls 만들기](#creating-partylocalchatcontrols-from-partyxbllocalchatusers)를 참조하세요.

원격 사용자의 경우:

```cpp theme={null}
void
OnRemoteXboxUserAddedToMPSD(
    uint64_t xboxUserId
    )
{
    PartyXblChatUser* remoteChatUser;
    PartyError err = PartyXblManager::GetSingleton().CreateRemoteChatUser(remoteXboxUserId, &remoteChatUser);
    if (PARTY_FAILED(err))
    {
        DEBUGLOG("CreateRemoteChatUser failed: %s\n", PartyXblManager::GetErrorMessage(err));
        return;
    }
```

이 시점에서 해당 원격 XBOX 사용자에 대해 PartyChatControl이 이미 존재하는 경우, SetCustomContext 메서드를 통해 이 PartyXblChatUser와 연결할 수 있습니다.

```cpp theme={null}
    remoteChatControl->SetCustomContext(remoteChatUser);
    remoteChatUser->SetCustomContext(remoteChatControl);
```

세션 문서에 대한 업데이트와 원격 채팅 컨트롤 목록에 대한 업데이트는 순서가 지정되지 않을 수 있으며, 원격 채팅 컨트롤에 대한 `PartyChatControlCreatedStateChange` 업데이트를 처리할 때 유사한 연결 로직이 필요할 수 있습니다.

로컬 및 원격 채팅 사용자 모두에 대해 핵심 Party 라이브러리는 PlayFab Entity ID를 통해 사용자와 채팅 컨트롤을 식별하는 반면 XBOX Live Helper 라이브러리는 XBOX User ID로 채팅 사용자를 식별한다는 점을 명심하는 것이 중요합니다. 따라서 이 둘 사이의 변환이 종종 필요합니다. 자세한 내용은 [XBOX Live User ID와 PlayFab Entity ID 간 매핑](#mapping-between-xbox-live-user-ids-and-playfab-entity-ids)을 참조하세요.

## PartyXblLocalChatUsers에서 PartyLocalChatControls 만들기

`PartyXblLocalChatUser` 객체는 Party 라이브러리의 `PartyLocalUser` 및 `PartyLocalChatControl` 객체와 연결될 때만 유용한 경우가 많습니다. `PartyLocalUser` 및 `PartyLocalChatControl` 객체를 생성하려면 타이틀이 PlayFab에 사용자를 로그인시키고 사용자의 `entityId`와 `titlePlayerEntityToken`을 검색해야 합니다. 로그인은 [PlayFab CPP SDK](/services/playfab/sdks/playfab-cpp)를 통해 수행할 수 있지만, 타이틀이 XBOX Live 자격 증명을 사용하여 PlayFab에 로그인하려는 경우 추가 종속성을 가져오는 것을 피하기 위해 `PartyXblManager::LoginToPlayFab`을 사용할 수 있습니다.

다음 샘플은 XBOX Live Helper 라이브러리가 `PartyXblLocalChatUser` 객체에서 `PartyLocalUser` 및 `PartyLocalChatControl` 객체를 만드는 데 어떻게 도움이 되는지 보여줍니다. `PartyXblLocalChatUser` 객체 만들기에 대한 자세한 내용은 [XBOX Live 사용자 추적](#keeping-track-of-xbox-live-users)을 참조하세요.

```cpp theme={null}
    err = PartyXblManager::GetSingleton().LoginToPlayFab(localChatUser, nullptr);
    if (PARTY_FAILED(err))
    {
        DEBUGLOG("LoginToPlayFab failed: %s\n", PartyXblManager::GetErrorMessage(err));
        return;
    }
```

`PartyXblManager::LoginToPlayFab` 호출 직후 로그인 작업 결과를 포함하는 `PartyXblLoginToPlayFabCompletedStateChange`를 받습니다.

```cpp theme={null}
    PartyLocalUser* partyLocalUser;
    if (stateChange->stateChangeType == PartyXblStateChangeType::LoginToPlayFabCompleted)
    {
        auto loginToPlayFabCompleted = static_cast<PartyXblLoginToPlayFabCompletedStateChange*>(stateChange);
        if (loginToPlayFabCompleted->result == PartyXblStateChangeResult::Succeeded)
        {
            err = PartyManager::GetSingleton().CreateLocalUser(
                loginToPlayFabCompleted->entityId,
                loginToPlayFabCompleted->titlePlayerEntityToken,
                partyLocalUser));
            if (PARTY_FAILED(err))
            {
                DEBUGLOG("CreateLocalUser failed: %s\n", PartyManager::GetErrorMessage(err));
                return;
            }
        }
    }

    PartyLocalDevice* localDevice;
    err = PartyManager::GetSingleton().GetLocalDevice(&localDevice);
    if (PARTY_FAILED(err))
    {
        DEBUGLOG("GetLocalDevice failed: %s\n", PartyManager::GetErrorMessage(err));
        return;
    }

    PartyLocalChatControl* localChatControl;
    err = localDevice->CreateChatControl(partyLocalUser, nullptr, nullptr, &localChatControl);
    if (PARTY_FAILED(err))
    {
        DEBUGLOG("CreateChatControl failed: %s\n", PartyManager::GetErrorMessage(err));
        return;
    }

    // We can use the custom context on the PartyXblLocalChatUser to store the PartyLocalChatControl for easy access
    // in the future.
    localChatUser->SetCustomContext(localChatControl);
```

## XBOX Live 사용자의 접근성 기본 설정 준수

`PartyXblLocalChatUser` 객체는 Party 채팅 세션과 관련된 XBOX Live 사용자의 접근성 기본 설정 일부를 노출합니다. 타이틀은 이 정보를 사용하여 Party의 접근성 기능 일부를 바로 활성화함으로써 플레이어에게 더 나은 경험을 제공할 수 있습니다.

```cpp theme={null}
    PartyXblAccessibilitySettings accessibilitySettings;
    err = localChatUser->GetAccessibilitySettings(&accessibilitySettings);
    if (PARTY_FAILED(err))
    {
        DEBUGLOG("GetAccessibilitySettings failed: %s\n", PartyXblManager::GetErrorMessage(err));
        return;
    }

    if (accessibilitySettings.speechToTextEnabled)
    {
        PartyVoiceChatTranscriptionOptions option = PartyVoiceChatTranscriptionOptions::TranscribeOtherChatControlsWithMatchingLanguages;
        m_localChatControl->SetTranscriptionOptions(option, nullptr);
    }
```

## XBOX Live 사용자의 개인 정보 보호 설정 및 권한 준수

XBOX Live 정책에 따라 타이틀은 사용자의 개인 정보 보호 또는 권한이 허용하지 않는 경우 XBOX Live를 통한 통신을 허용해서는 안 됩니다. XBOX Live Helper 라이브러리는 XBOX Live 정책이 허용하는 두 사용자 간의 가장 제한적인 `PartyChatPermissionOptions`를 쿼리할 수 있게 하여 이를 달성하는 데 도움이 됩니다. 이 값이 변경될 때마다 라이브러리에서 `PartyXblRequiredChatPermissionInfoChangedStateChange`가 생성됩니다. 업데이트된 `PartyChatPermissionOptions`는 `PartyXblLocalChatUser::GetRequiredChatPermissionInfo()` 호출을 통해 얻을 수 있습니다.

```cpp theme={null}
    PartyXblChatUser* remoteChatUser;
    PartyError err = PartyXblManager::GetSingleton().CreateRemoteChatUser(remoteXboxUserId, &remoteChatUser);
    if (PARTY_FAILED(err))
    {
        DEBUGLOG("CreateRemoteChatUser failed: %s\n", PartyXblManager::GetErrorMessage(err));
        return;
    }

    // Once the chat control representing this remote Xbox Live user joins a network, we can use the custom context
    // on the PartyXblChatUser to store the chat control object for quick access in the future.
    remoteChatUser->SetCustomContext(m_remotePartyChatControl);
```

XBOX Live Helper 라이브러리는 XBOX Live 개인 정보 보호 서비스와 통신하여 각 로컬 채팅 사용자와 관련된 각 원격 채팅 사용자의 개인 정보 보호 및 권한 설정을 추적합니다. 또한 라이브러리는 [Real-Time Activity](/services/xbox-services/fundamentals/rta/live-rta-nav) 업데이트를 구독하여 이러한 설정에 대한 변경 사항을 수신합니다. 새 원격 채팅 사용자가 추가되거나 로컬 채팅 사용자와 기존 원격 채팅 사용자 간의 개인 정보 보호 및 권한 관계가 변경되면 업데이트된 `PartyChatPermissionOptions` 값을 이제 사용할 수 있음을 알리기 위해 `PartyXblRequiredChatPermissionInfoChangedStateChange`가 생성됩니다.

```cpp theme={null}
    // Wait for PartyXblRequiredChatPermissionInfoChangedStateChange
    if (stateChange->stateChangeType == PartyXblStateChangeType::RequiredChatPermissionInfoChanged)
    {
        auto chatPermissionChanged = static_cast<PartyXblRequiredChatPermissionInfoChangedStateChange*>(stateChange);

        PartyXblLocalChatUser* localChatUser = chatPermissionChanged->localChatUser;
        PartyXblChatUser* targetChatUser = chatPermissionChanged->targetChatUser;

        PartyXblChatPermissionInfo chatPermissionInfo;
        PartyError err = localChatUser->GetRequiredChatPermissionInfo(targetChatUser, &chatPermissionInfo);
        if (PARTY_FAILED(err))
        {
            DEBUGLOG("GetRequiredChatPermissionInfo failed: %s\n", PartyXblManager::GetErrorMessage(err));
            return;
        }

        PartyLocalChatControl* localChatControl;
        localChatUser->GetCustomContext(reinterpret_cast<void**>(&localChatControl));
        if (PARTY_FAILED(err))
        {
            DEBUGLOG("GetCustomContext failed: %s\n", PartyXblManager::GetErrorMessage(err));
            return;
        }

        PartyChatControl* targetChatControl;
        targetChatUser->GetCustomContext(reinterpret_cast<void**>(&targetChatControl));
        if (PARTY_FAILED(err))
        {
            DEBUGLOG("GetCustomContext failed: %s\n", PartyXblManager::GetErrorMessage(err));
            return;
        }

        localChatControl->SetPermission(targetChatControl, chatPermissionInfo.chatPermissionMask);
        if (PARTY_FAILED(err))
        {
            DEBUGLOG("SetPermission failed: %s\n", PartyXblManager::GetErrorMessage(err));
            return;
        }
    }
```

`PartyXblChatPermissionInfo` 구조체에는 두 가지 정보가 포함되어 있습니다.

* `PartyChatPermissionOptions` 마스크로, `PartyLocalChatControl::SetPermission()`에 그대로 전달하거나 사용하려는 `PartyChatPermissionOptions` 값이 이미 있지만 XBOX Live 정책을 준수하고 있는지 확인하려는 경우 이진 마스크로 사용할 수 있습니다.
* `PartyXblChatPermissionInfo::chatPermissionMask`의 값에 대한 추가 정보를 제공하는 `PartyXblChatPermissionMaskReason` 값

| **PartyXblChatPermissionMaskReason** | **설명**                                             |
| :----------------------------------- | :------------------------------------------------- |
| NoRestriction                        | 이 채팅 권한에 현재 적용되는 제한이 없습니다.                         |
| Determining                          | 로컬 사용자의 통신 권한 및 개인 정보 보호 설정이 결정되는 동안 통신이 제한됩니다.    |
| Privilege                            | 로컬 사용자의 통신 권한으로 인해 통신이 제한됩니다.                      |
| Privacy                              | 대상 채팅 사용자와 관련된 로컬 사용자의 개인 정보 보호 설정으로 인해 통신이 제한됩니다. |
| InvalidTargetUser                    | 대상 사용자가 XBOX Live 서비스에서 유효한 것으로 인식되지 않아 통신이 제한됩니다. |
| XboxLiveServiceError                 | XBOX Live 서비스 문제로 인해 필수 채팅 권한을 성공적으로 결정할 수 없었습니다.  |
| UnknownError                         | 알 수 없는 내부 오류로 인해 필수 채팅 권한을 성공적으로 결정할 수 없었습니다.      |

## 크로스 네트워크 통신 권한 준수

XBOX Live와 XBOX Live가 아닌 플레이어 간의 크로스 네트워크 플레이 및 통신을 지원하는 타이틀은 해당 플레이어 간 통신을 허용하기 전에 통신 권한을 확인해야 합니다. XBOX Live Helper 라이브러리는 `PartyXblLocalChatUser::GetCrossNetworkCommunicationPrivacySetting()`을 통해 이 정보를 제공합니다. 이 메서드는 세 가지 가능한 값을 가진 `PartyXblCrossNetworkCommunicationPrivacySetting` 열거형을 반환합니다.

| **PartyXblCrossNetworkCommunicationPrivacySetting** | **설명**                                                       |
| :-------------------------------------------------- | :----------------------------------------------------------- |
| Allowed                                             | 이 XBOX Live 사용자의 권한은 모든 크로스 네트워크 플레이어와의 통신을 허용하도록 설정되어 있습니다. |
| FriendsOnly                                         | 이 XBOX Live 사용자의 권한은 크로스 네트워크 친구와만 통신을 허용하도록 설정되어 있습니다.      |
| Disallowed                                          | 이 XBOX Live 사용자의 권한은 크로스 네트워크 플레이어와의 통신을 허용하지 않습니다.          |

```cpp theme={null}
    PartyXblCrossNetworkCommunicationPrivacySetting crossNetworkSetting;
    localChatUser->GetCrossNetworkCommunicationPrivacySetting(&crossNetworkSetting);

    if (crossNetworkSetting == PartyXblCrossNetworkCommunicationPrivacySetting::Disallowed)
    {
        m_localChatControl->SetPermissions(crossNetworkChatControl, PartyChatPermissionOptions::None);
    }
```

XR-015 및 크로스 네트워크 플레이 및 통신과 관련된 방식에 대한 자세한 정보는 [여기](https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/live/get-started/live-xbl-overview)에서 확인할 수 있습니다.

## XBOX Live User ID와 PlayFab Entity ID 간 매핑

PlayFab Party를 사용하는 많은 XBOX Live 타이틀은 (XBOX Live 생태계 전반에서 사용되는) XBOX Live User ID와 (PlayFab Party에서 사용되는) PlayFab Entity ID 간에 변환해야 합니다. `PartyXblManager::GetEntityIdsFromXboxLiveUserIds`를 사용하여 타이틀은 주어진 XBOX Live User ID 목록에 해당하는 PlayFab Entity ID 목록을 검색할 수 있습니다. 타이틀은 [Multiplayer Session Directory](https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/live/get-started/live-xbl-overview) 같은 외부 명단 서비스 사용을 통해 이미 XBOX Live User ID 목록을 가지고 있어야 합니다. 명단의 XBOX Live User ID를 그들의 PlayFab Entity ID와 연결하여, 게임 세션의 명단에 해당하는 모든 PlayFab Entity ID의 매핑을 구성할 수 있습니다. 그런 다음 이 매핑을 사용하여 `PartyEndpoint` 및 `PartyChatControl` 객체를 해당 XBOX Live 사용자와 연결할 수 있습니다.

<Note>
  각 XBOX Live User ID는 이 XBOX Live 사용자가 이미 PlayFab 계정에 연결된 경우에만 PlayFab Entity ID에 매핑됩니다. PlayFab 계정은 주어진 XBOX 사용자에 대해 `PartyXblManager::LoginToPlayFab`가 처음 호출될 때 자동으로 생성되고 연결됩니다. 또는 PlayFab SDK 소비자는 [LoginWithXbox](https://learn.microsoft.com/en-us/rest/api/playfab/client/authentication/login-with-xbox?view=playfab-rest\&preserve-view=true) API를 사용하여 동일한 결과를 얻을 수 있습니다.
</Note>

로컬 `PartyXblLocalChatUser`는 PlayFab로 인증하는 데 사용됩니다. 사용자가 이전에 `PartyXblManager::LoginToPlayFab` 호출을 통해 PlayFab에 로그인하지 않은 경우 XBOX Live Helper 라이브러리는 백그라운드에서 사용자를 인증해야 합니다.

```cpp theme={null}
    uint32_t userCount;
    PartyXblChatUserArray chatUsers;
    PartyError err = PartyXblManager::GetSingleton().GetChatUsers(&userCount, &users);
    if (PARTY_FAILED(err))
    {
        DEBUGLOG("GetChatUsers failed: %s\n", PartyXblManager::GetErrorMessage(err));
        return;
    }

    // The list of remote Xbox Live User IDs. This can be populated with arbitrary IDs
    // std::vector<uint64_t> remoteXboxLiveUserIds = {2533274792693551, 2814659110958830};
    //
    // but can also be pulled from the list of remote chat users
    std::vector<uint64_t> remoteXboxLiveUserIds;
    for (uint32_t i = 0; i < userCount; ++i)
    {
        PartyXblChatUser* chatUser = users[i];

        PartyXblLocalChatUser* localChatUser;
        err = chatUser->GetLocal(&localChatUser);
        if (PARTY_FAILED(err))
        {
            DEBUGLOG("PartyChatUser(0x%p)::GetLocal failed: %s\n", chatUser, PartyXblManager::GetErrorMessage(err));
            return;
        }

        if (localChatUser != nullptr)
        {
            continue; // ignore local users
        }

        uint64_t userId;
        err = chatUser->GetXboxUserId(&userId);
        if (PARTY_FAILED(err))
        {
            DEBUGLOG("PartyChatUser(0x%p)::GetXboxUserId failed: %s\n", chatUser, PartyXblManager::GetErrorMessage(err));
            return;
        }

        remoteXboxLiveUserIds.push_back(userId);
    }

    err = PartyXblManager::GetSingleton().GetEntityIdsFromXboxLiveUserIds(
        remoteXboxLiveUserIds.size(),
        remoteXboxLiveUserIds.data(),
        localChatUser,
        nullptr);
    if (PARTY_FAILED(err))
    {
        DEBUGLOG("GetEntityIdsFromXboxLiveUserIds failed: %s\n", PartyXblManager::GetErrorMessage(err));
        return;
    }
```

`PartyXblManager::GetEntityIdsFromXboxLiveUserIds` 호출 직후 작업 결과를 포함하는 `PartyXblGetEntityIdsFromXboxLiveUserIdsCompletedStateChange`를 받게 됩니다. 이 결과는 매핑을 구성하거나 업데이트하는 데 사용할 수 있습니다.

```cpp theme={null}
    // Wait for PartyXblGetEntityIdsFromXboxLiveUserIdsCompletedStateChange
    if (stateChange->stateChangeType == PartyXblStateChangeType::GetEntityIdsFromXboxLiveUserIdsCompleted)
    {
        std::vector<std::pair<uint64_t, std::string>> cachedXboxUserIdToPlayFabEntityIdMap;

        auto getEntityIdsFromXboxLiveUserIdsResult = static_cast<PartyXblGetEntityIdsFromXboxLiveUserIdsCompletedStateChange*>(stateChange);
        for (uint32_t i = 0; i < getEntityIdsFromXboxLiveUserIdsResult.entityIdMappingCount; ++i)
        {
            const PartyXblXboxUserIdToPlayFabEntityIdMapping& idMapping = getEntityIdsFromXboxLiveUserIdsResult.entityIdMappings[i];

            Log("   Xbox Live User ID: %llu", idMapping.xboxLiveUserId);
            if (strlen(idMapping.playfabEntityId)) != 0)
            {
                Log("    PlayFab Entity ID: %s", idMapping.playfabEntityId);
                cachedXboxUserIdToPlayFabEntityIdMap.emplace_back(idMapping.xboxLiveUserId, idMapping.playfabEntityId);
            }
            else
            {
                // This Xbox Live User did not have a linked PlayFab Account.
                Log("    PlayFab Entity ID: NOT FOUND");
            }
        }

        m_cachedXboxUserIdToPlayFabEntityIdMap = std::move(cachedXboxUserIdToPlayFabEntityIdMap);
```

이러한 매핑을 통해 타이틀은 Party 객체가 XBOX Live 사용자를 나타내는 시기를 인식할 수 있습니다.

```cpp theme={null}
uint64_t
GetXboxUserIdFromPlayFabEntityId(
    PartyString entityId
    )
{
    for (const std::pair<uint64_t, std::string>& idMapping : m_cachedXboxUserIdToPlayFabEntityIdMap)
    {
        const std::string& entityIdForXboxUserId = idMapping.second;
        if (entityIdForXboxUserId == entityId)
        {
            return idMapping.first;
        }
    }

    // Failed to find a matching Xbox User ID. This Entity ID does not represent an Xbox Live user.
    return 0;
}
```

## Windows에 대한 특수 고려 사항

Windows에서는 XBOX Live Helper 라이브러리가 XBOX Live 토큰을 얻는 데 타이틀의 도움이 필요합니다. 라이브러리는 `PartyXblTokenAndSignatureRequestedStateChange`를 생성하여 토큰을 요청합니다. 타이틀은 [XBOX Authentication Library](https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/live/get-started/live-xbl-overview)(XAL)를 사용하여 이러한 요청을 이행할 수 있습니다. 이 작업을 타이틀로 오프로드하면 사용자 인증과 일반적으로 연관된 모든 UI 처리와 동의 프롬프트를 완전히 제어할 수 있습니다.

```cpp theme={null}
    if (stateChange->stateChangeType == PartyXblStateChangeType::TokenAndSignatureRequested)
    {
        auto tokenAndSignatureRequested = static_cast<PartyXblTokenAndSignatureRequestedStateChange*>(stateChange);

        // Convert the headers to the format XAL expect
        std::vector<XalHttpHeader> xalHeaders;
        for (uint32_t i = 0; i < stateChange.headerCount; ++i)
        {
            xalHeaders.push_back({stateChange.headers[i].name, stateChange.headers[i].value});
        }

        XalUserGetTokenAndSignatureArgs args = {};
        args.method = stateChange.method;
        args.url = stateChange.url;
        args.headerCount = static_cast<uint32_t>(xalHeaders.size());
        args.headers = xalHeaders.data();
        args.bodySize = stateChange.bodySize;
        args.body = static_cast<const uint8_t*>(stateChange.body);
        args.forceRefresh = stateChange.forceRefresh != 0;
        args.allUsers = stateChange.allUsers != 0;

        XAsyncBlock* asyncBlock = new XAsyncBlock;
        asyncBlock->queue = m_queue;
        HRESULT hr = XalUserGetTokenAndSignatureSilentlyAsync(m_userHandle, &args, asyncBlock);
    }
```

XAL을 사용하여 토큰과 서명을 검색하는 방법에 대한 자세한 지침은 [XBOX Authentication Library 문서](https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/live/get-started/live-xbl-overview)를 참조하세요.

토큰과 서명이 있으면 상태 변경을 통해 타이틀에 제공된 동일한 `correlationId`와 함께 `PartyXblManager::CompleteGetTokenAndSignatureRequest()`를 호출하여 XBOX Live Helper 라이브러리에 제공할 수 있습니다.


## Related topics

- [PlayFab Party XBOX Live Helper Release Notes](/ko/services/playfab/multiplayer/networking/party-xboxlive-relnotes.md)
- [PlayFab Party XBOX Live Helper Typedefs](/ko/services/playfab/multiplayer/networking/xblreference/xbltypedefs.md)
- [PlayFab Party XBOX Live Helper 오류 코드](/ko/services/playfab/multiplayer/networking/xblreference/partyxblerrors.md)
- [XBOX services 타이틀을 위한 PlayFab 통합](/ko/services/xbox-services/playfab-integration.md)
- [XBOX 요구 사항](/ko/services/playfab/multiplayer/networking/xbox-requirements.md)
