Xbox Live ヘルパー ライブラリの概要

PlayFab Party 向け Xbox Live ヘルパー ライブラリは、PlayFab Party を使用するゲームが、通信 (XR-015 およびXR-045) に関連したXbox Live ポリシーをサポートするために設計されています。 Xbox Live ヘルパー ライブラリは Nuget.org で利用できます。

PlayFab Party ライブラリとの互換性

Microsoft では API の変更を最小限に抑えるよう努めていますが、PlayFab Party API に加えられたいくつかの変更により、Xbox Live ヘルパー ライブラリが誤った値を返す可能性があります。 以下のテーブルを参照して、ライブラリのバージョンが一致していることを確認してください。

Xbox Live ヘルパー ライブラリ
バージョン
PlayFab パーティー バージョン
1.0.1
PlayFab パーティー バージョン
1.3.0+
1.0.1
1.1.0
1.2.0
1.2.5

Xbox Live ユーザーの追跡を維持する

PlayFab Party の Xbox Live ヘルパー ライブラリは、現在 Party セッションに参加している Xbox Live ユーザーを明示的に通知される必要があります。 タイトルは、マルチプレイヤー セッション ドキュメントへの変更をリッスンし、その名簿を PartyXblManager::CreateLocalChatUser および PartyXblManager::CreateRemoteChatUser 経由で Xbox Live ヘルパー ライブラリに反映することによってライブラリに通知することをお勧めします。

ローカル ユーザー向けの機能は、以下のとおりです。

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 に関連付けることができます。

    localChatControl->SetCustomContext(localChatUser);
    localChatUser->SetCustomContext(localChatControl);

そうでない場合は、この新しい PartyXblLocalChatUser を使用して、チャット コントロールを生成し、関連付けることができます。 詳細については、「PartyXblLocalChatUsers で PartyXblLocalChatUsers を作成する」を参照してください。

リモート ユーザー向けの機能は、以下のとおりです。

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 に関連付けることができます。

    remoteChatControl->SetCustomContext(remoteChatUser);
    remoteChatUser->SetCustomContext(remoteChatControl);

なお、セッション ドキュメントの更新とリモート チャット コントロールのリストの更新は順序付けられていない可能性があり、リモート チャット コントロールの PartyChatControlCreatedStateChange 件の更新を処理する場合に、同様の関連付けロジックが必要になる可能性があります。

ローカルとリモートの両方のチャット ユーザーについて、コア パーティー ライブラリは PlayFab エンティティ ID でユーザーとチャット コントロールを識別し、Xbox Live ヘルパー ライブラリは Xbox ユーザー ID でチャット ユーザーを特定することに留意しておくことが重要です。 そのため、これら 2 つの間で翻訳が必要になることがあります。 詳細については、「Xbox Live ユーザー ID と PlayFab エンティティ ID のマッピング」を参照してください。

PartyXblLocalChatUsers で PartyXblLocalChatUsers を作成する

PartyXblLocalChatUser オブジェクトは、Party ライブラリの PartyLocalUserPartyLocalChatControl オブジェクトと関連付けた場合のみ役に立ちます。 PartyLocalUserPartyLocalChatControl のオブジェクトを生成するには、タイトルが PlayFab にユーザーをログインさせ、ユーザーの entityIdtitlePlayerEntityToken を取得する必要があります。 ログインは PlayFab CPP SDK を介して実行できますが、タイトルが Xbox Live 資格情報を使用して PlayFab にログインしようとする場合は、余分な依存関係を取得しないように PartyXblManager::LoginToPlayFab を使用することができます。

次の例では、Xbox Live ヘルパー ライブラリを使用して、PartyXblLocalChatUser オブジェクトから PartyLocalUser および PartyLocalChatControl オブジェクトの作成をサポートすることが可能です。 PartyXblLocalChatUser オブジェクトの作成については、「Xbox Live ユーザーの追跡の維持」を参照してください。

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

PartyXblManager::LoginToPlayFab を呼び出した後すぐに、ログイン操作の結果を含む PartyXblLoginToPlayFabCompletedStateChange を受信します。

    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 オブジェクトは、パーティー チャット セッションに関連する、Xbox Live ユーザーのアクセシビリティ設定の一部を公開します。 タイトルはこの情報をもとに、Party のアクセシビリティ機能の一部をすぐに有効にすることで、プレーヤーにより良いエクスペリエンスを提供することができます。

    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 ヘルパー ライブラリは、Xbox Live ポリシーで許可されている 2 人のユーザー間の最も制限された PartyChatPermissionOptions を照会できるようにすることで、その実現をサポートします。 この値が変化するたびに、ライブラリで PartyXblRequiredChatPermissionInfoChangedStateChange が生成されます。 更新された PartyChatPermissionOptionsPartyXblLocalChatUser::GetRequiredChatPermissionInfo() の呼び出しによって取得されます。

    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 ヘルパー ライブラリは、Xbox Live プライバシー サービスと通信することで、各リモート チャット ユーザーのプライバシーやアクセス許可の設定を、各ローカル チャット ユーザーとの通信により追跡します。 さらに、ライブラリは リアルタイム アクティビティ の更新をサブスクライブすることで、これらの設定の変更を確認します。 新しいリモート チャット ユーザーが追加されたり、ローカル チャット ユーザーと既存のリモート チャット ユーザーの間のプライバシーとアクセス許可の関係が変更された場合、PartyXblRequiredChatPermissionInfoChangedStateChange が生成され、更新された PartyChatPermissionOptions の値が利用可能になったことが通知されます。

    // 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 構造には、以下の 2 つの情報が含まれます。

  • PartyChatPermissionOptions マスクは、そのまま PartyLocalChatControl::SetPermission() に渡すこともできますし、すでに PartyChatPermissionOptions の値を持っていて使用したいものの、Xbox Live ポリシーを尊重していることを確認したい場合には、バイナリ マスクとして使用することもできます。
  • PartyXblChatPermissionInfo::chatPermissionMask の値に関する追加情報を提供する PartyXblChatPermissionMaskReason の値
PartyXblChatPermissionMaskReason 説明
NoRestriction 現在、このチャットのアクセス許可に適用される制限はありません。
判定 ローカル ユーザーの通信特権やプライバシー設定の判定中に通信が制限される
特権 ローカル ユーザーの通信特権により、通信が制限されています。
プライバシー ローカル ユーザーのプライバシー設定により、対象のチャット ユーザーとの通信が制限されます。
InvalidTargetUser 対象ユーザーが Xbox Live サービスによって有効であると認識されなかったため、通信は制限されます。
XboxLiveServiceError Xbox Live サービスに問題があるため、必要なチャットのアクセス許可を正常に判定できませんでした。
UnknownError 不明な内部エラーのため、必要なチャットのアクセス許可を正常に判定できませんでした。

クロスネットワークでの通信アクセス許可の尊重

Xbox Live プレイヤーと非 Xbox Live プレイヤー間のクロス ネットワーク プレイと通信をサポートするタイトルは、こうしたプレイヤー間の通信を許可する前に、通信権限を確認する必要があります。 Xbox Live ヘルパー ライブラリでは、PartyXblLocalChatUser::GetCrossNetworkCommunicationPrivacySetting() 経由でこの情報を提供します。 このメソッドは、以下の 3 つの可能な値を含む PartyXblCrossNetworkCommunicationPrivacySetting 列挙体を返します。

PartyXblCrossNetworkCommunicationPrivacySetting 説明
許可 この Xbox Live のユーザー権限が、すべてのクロスネットワーク プレイヤーとの通信を許可するように設定されています。
FriendsOnly この Xbox Live のユーザー権限が、クロスネットワークのフレンドとの通信のみを許可するように設定されています。
不許可 この Xbox Live のユーザー権限が、クロスネットワーク プレイヤーとの通信を一切許可しません。
    PartyXblCrossNetworkCommunicationPrivacySetting crossNetworkSetting;
    localChatUser->GetCrossNetworkCommunicationPrivacySetting(&crossNetworkSetting);

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

XR-015 の詳細、およびクロスネットワーク プレイと通信に関連する情報は、こちらをご覧ください。

Xbox Live ユーザー ID と PlayFab エンティティ ID のマッピング

PlayFab Party を使用する Xbox Live タイトルの多くでは、Xbox Live ユーザー ID (Xbox Live のエコシステム全体で使用) と PlayFab エンティティ ID (PlayFab Party で使用) の間で変換する必要があります。 PartyXblManager::GetEntityIdsFromXboxLiveUserIds を使用して、タイトルは、与えられた Xbox Live ユーザー ID のリストに対応する PlayFab エンティティ ID のリストを取得することができます。 タイトルは、マルチプレイヤー セッション ディレクトリのような外部の名簿サービスを利用して、Xbox Live ユーザー ID のリストをすでに所有していることが予想されます。 名簿から Xbox Live ユーザー ID をその PlayFab エンティティ ID と関連付けることで、ゲーム セッションの名簿に対応するすべての PlayFab エンティティ ID のマッピングを構築することができます。 このマッピングを使用して、PartyEndpoint および PartyChatControl オブジェクトと、対応する Xbox Live ユーザーを関連付けることができます。

注意

各 Xbox Live ユーザー ID は、この Xbox Live ユーザーがすでに PlayFab アカウントにリンクされている場合にのみ、PlayFab エンティティ ID にマッピングされます。 PlayFab アカウントは、特定の Xbox ユーザーに対して PartyXblManager::LoginToPlayFab が初めて呼び出されたときに自動的に作成され、リンクされます。 また、PlayFab SDK のコンシューマーは LoginWithXbox API を使用して同じ結果を得ることもできます。

ローカル PartyXblLocalChatUser は PlayFab を使用した認証に使用されます。 ユーザーが PartyXblManager::LoginToPlayFab への呼び出しで以前に PlayFab にログインしていなかった場合、Xbox Live ヘルパー ライブラリはバックグラウンドでユーザーを認証する必要があります。

    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 を受信します。 この結果は、マッピングの構築や更新に利用できます。

    // 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 ユーザーであることをタイトルが認識することができます。

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 ヘルパー ライブラリは、Xbox Live トークンを取得するためにタイトルからのヘルプが必要です。 ライブラリは PartyXblTokenAndSignatureRequestedStateChange を生成してトークンを要求します。 タイトルは、Xbox 認証ライブラリ (XAL) を使用して、これらの要求を満たすことができます。 この作業をタイトルにオフロードすることで、通常のユーザー認証に伴う UI 処理や同意を求めるプロンプトをタイトルが完全にコントロールできるようになります。

    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 認証ライブラリのドキュメント」を参照してください。

トークンと署名を取得したら、状態変更を通してタイトルに指定されたものと同じ correlationId を使用して PartyXblManager::CompleteGetTokenAndSignatureRequest() を呼び出すことで、Xbox Live ヘルパー ライブラリに提供することができます。