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

# MPSD から PlayFab Multiplayer と MPA への移行

> XBOX タイトルを MPSD から PlayFab Multiplayer ロビーおよび Multiplayer Activity (MPA) に移行して招待、マッチメーキング、最近のプレイヤーを実装するための移行ガイド。

## はじめに

このドキュメントは、現在 MPSD を使用しており、マルチプレイヤーゲームで PlayFab Multiplayer と MPA を使用するように移行したいゲーム開発者向けです。このドキュメントでは、最も一般的なマルチプレイヤーのシナリオを取り上げ、PlayFab Multiplayer を MPA とともに使用する方法を示すコードスニペットを提供します。

### Multiplayer Session Directory (MPSD) の概要

* ユーザーグループを接続するために必要な情報を共有するための、フル機能を備えたセッションサービス
* 招待や参加機能のために XBOX UI と統合
* SmartMatch マッチメーキングと完全に統合
* セッションは事前定義されたセッションテンプレートから派生
* 接続検出とセッションフローのための機能が統合
* サービス間で利用可能

### Multiplayer Activity Service (MPA) の概要

* プレイヤーアクティビティ、招待、および最近のプレイヤーに関する XBOX Live 統合を簡素化するための軽量サービス
* 招待の送信/受け入れおよび参加時にシェルおよびコンソールオペレーティングシステムと連携
* セッション管理やマッチメーキングは行わない
* サービス間で利用可能

### PlayFab Multiplayer の概要

* ロビーの検索や閲覧機能を含む、完全なマルチプレイヤーロビーサービス
* 透過的な API 統合を備えたクロスプラットフォームのリアルタイムサービス通知
* リアルタイム通知をサポートする完全なマッチメーキングサービス

## 初期化

次の表は、初期化のために MPSD および PlayFab Multiplayer で使用される類似の関数のリストを示しています。

| MPSD                                          | PlayFab Multiplayer           |
| --------------------------------------------- | ----------------------------- |
| `XblMultiplayerAddSubscriptionLostHandler`    | `PFMultiplayerInitialize`     |
| `XblMultiplayerAddConnectionIdChangedHandler` | `PFMultiplayerSetEntityToken` |
| `XblMultiplayerSetSubscriptionsEnabled`       |                               |
| `XblMultiplayerSessionCurrentUserSetStatus`   |                               |

### 初期化 - サンプルコード

PlayFab titleID でライブラリを初期化し、PlayFab サービスへのログイン中に受け取ったエンティティトークンを設定します。

```cpp theme={null}
PFMultiplayerHandle pfmHandle{};
HRESULT hr = PFMultiplayerInitialize(pfTitleId, &pfmHandle);
if (FAILED(hr))
{
    //...
}

hr = PFMultiplayerSetEntityToken(pfmHandle, &entityKey, entityToken);
if (FAILED(hr))
{
    //...
}
```

## ロビーの状態変更

次の表は、セッション/ロビーに関連するイベントを処理するために MPSD および PlayFab Multiplayer で使用される類似の関数のリストを示しています。

| MPSD                                           | PlayFab Multiplayer                              |
| ---------------------------------------------- | ------------------------------------------------ |
| `XblMultiplayerSessionSubscribedChangeTypes`   | `PFMultiplayerStartProcessingLobbyStateChanges`  |
| `XblMultiplayerSessionChangedHandler`          | `PFMultiplayerFinishProcessingLobbyStateChanges` |
| `XblMultiplayerSessionSubscriptionLostHandler` |                                                  |

### ロビーの状態変更 - サンプルコード

状態変更の処理を開始することをライブラリに通知します。キューに入れられた各状態変更を処理してから、状態変更の処理が完了したことを通知します。

```cpp theme={null}
HRESULT hr = PFMultiplayerStartProcessingLobbyStateChanges(MultiplayerHandle, &StateChangeCount, &StateChanges);
if (FAILED(hr))
{
    //...
}

for (uint32_t i = 0; i < StateChangeCount; ++i)
{
    const PFLobbyStateChange& Change = *StateChanges[i];

    switch (Change.stateChangeType)
    {
    case PFLobbyStateChangeType::CreateAndJoinLobbyCompleted:        /*...*/ break;
    case PFLobbyStateChangeType::JoinLobbyCompleted:                 /*...*/ break;
    case PFLobbyStateChangeType::MemberAdded:                        /*...*/ break;
    case PFLobbyStateChangeType::AddMemberCompleted:                 /*...*/ break;
    case PFLobbyStateChangeType::MemberRemoved:                      /*...*/ break;
    case PFLobbyStateChangeType::ForceRemoveMemberCompleted:         /*...*/ break;
    case PFLobbyStateChangeType::LeaveLobbyCompleted:                /*...*/ break;
    case PFLobbyStateChangeType::Updated:                            /*...*/ break;
    case PFLobbyStateChangeType::PostUpdateCompleted:                /*...*/ break;
    case PFLobbyStateChangeType::Disconnecting:                      /*...*/ break;
    case PFLobbyStateChangeType::Disconnected:                       /*...*/ break;
    case PFLobbyStateChangeType::JoinArrangedLobbyCompleted:         /*...*/ break;
    case PFLobbyStateChangeType::FindLobbiesCompleted:               /*...*/ break;
    case PFLobbyStateChangeType::InviteReceived:                     /*...*/ break;
    case PFLobbyStateChangeType::InviteListenerStatusChanged:        /*...*/ break;
    case PFLobbyStateChangeType::SendInviteCompleted:                /*...*/ break;
    case PFLobbyStateChangeType::CreateAndClaimServerLobbyCompleted: /*...*/ break;
    case PFLobbyStateChangeType::ClaimServerLobbyCompleted:          /*...*/ break;
    case PFLobbyStateChangeType::ServerPostUpdateCompleted:          /*...*/ break;
    case PFLobbyStateChangeType::ServerDeleteLobbyCompleted:         /*...*/ break;
    }
}

hr = PFMultiplayerFinishProcessingLobbyStateChanges(MultiplayerHandle, StateChangeCount, StateChanges);
if (FAILED(hr))
{
    //...
}
```

## ロビーの作成

次の表は、セッション/ロビーの作成および参加のために MPSD および PlayFab Multiplayer で使用される類似の関数のリストを示しています。

| MPSD                                                | PlayFab Multiplayer               |
| --------------------------------------------------- | --------------------------------- |
| `XblMultiplayerSessionReferenceCreate`              | `PFMultiplayerCreateAndJoinLobby` |
| `XblMultiplayerSessionCreateHandle`                 |                                   |
| `XblMultiplayerSessionJoin`                         |                                   |
| `XblMultiplayerAddSessionChangedHandler`            |                                   |
| `XblMultiplayerSessionSetSessionChangeSubscription` |                                   |
| `XblMultiplayerSessionSetHostDeviceToken`           |                                   |
| `XblMultiplayerWriteSessionAsync`                   |                                   |

<Note>ロビーを作成するのに、PlayFab Game Manager での追加のセットアップや構成は必要ありません。すべての構成はコード内で行うことができます。</Note>

### ロビーの作成 - サンプルコード

ロビーを構成し、任意の初期ロビープロパティまたはメンバープロパティを設定してから、ロビーを作成して参加します。

```cpp theme={null}
PFLobbyCreateConfiguration createConfig{};
createConfig.maxMemberCount = 4;
createConfig.ownerMigrationPolicy = PFLobbyOwnerMigrationPolicy::Automatic;
createConfig.accessPolicy = PFLobbyAccessPolicy::Public;

const char* memberPropertyKeys[] { "favoriteColor" };
const char* memberPropertyValues[] { "blue" };

PFLobbyJoinConfiguration joinConfig{};
joinConfig.memberPropertyCount = 1;
joinConfig.memberPropertyKeys = memberPropertyKeys;
joinConfig.memberPropertyValues = memberPropertyValues;

PFLobbyHandle myLobby{};

HRESULT hr = PFMultiplayerCreateAndJoinLobby(
    pfmHandle,           // PFMultiplayerHandle
    &localUserEntityKey, // local user 
    &createConfig,       // create config
    &joinConfig,         // join config
    nullptr,             // async context (optional)   
    &myLobby);           // lobby handle

if (FAILED(hr))
{
    //...
}
```

## ロビーの検索

次の表は、セッション/ロビーを検索するために MPSD および PlayFab Multiplayer で使用される類似の関数のリストを示しています。

| MPSD                                                       | PlayFab Multiplayer        |
| ---------------------------------------------------------- | -------------------------- |
| `XblMultiplayerGetSearchHandlesAsync`                      | `PFMultiplayerFindLobbies` |
| `XblMultiplayerSearchHandleGetId`                          |                            |
| `XblMultiplayerSearchHandleGetCustomSessionPropertiesJson` |                            |
| `XblMultiplayerSearchHandleGetMemberCounts`                |                            |
| `XblMultiplayerSearchHandleGetSessionClosed`               |                            |

### ロビーの検索 - サンプルコード

検索構成を設定してからロビーを検索します。

```cpp theme={null}
PFLobbySearchConfiguration searchConfiguration{};
searchConfiguration.filterString = filterString.c_str(); // filtering
searchConfiguration.sortString = sortString.c_str();     // sorting
searchConfiguration.clientSearchResultCount = 50;        // limits the number of results
searchConfiguration.friendsFilter;                       // return only lobbies with friends in them

HRESULT hr = PFMultiplayerFindLobbies(
    pfmHandle,          // PFMultiplayerHandle
    &localUserEntityKey,  // local user
    &searchConfiguration, // search config
    nullptr);             // async context (optional)

if (FAILED(hr))
{
    //...
} 
```

次に、イベントの状態変更が返されたら、任意の検索結果を処理します。

```cpp theme={null}
const auto& stateChange = static_cast<const PFLobbyFindLobbiesCompletedStateChange&>(change);
if (SUCCEEDED(stateChange.result))
{
    for (uint32_t i = 0; i < stateChange.searchResultCount; ++i)
    {
        const PFLobbySearchResult& searchResult = stateChange.searchResults[i];
        searchResult.lobbyId;            // lobby id
        searchResult.connectionString;   // connection string
        searchResult.ownerEntity;        // lobby host
        searchResult.maxMemberCount;     // lobby size
        searchResult.currentMemberCount; // players in lobby
        
        for (uint32_t j = 0; j < searchResult.searchPropertyCount; ++j) 
        {
            const char* searchPropertyKey = searchResult.searchPropertyKeys[j];
            const char* searchPropertyValue = searchResult.searchPropertyValues[j];
            /*...*/
        }
        
        for (uint32_t k = 0; k < searchResult.friendCount; ++k) 
        {
            PFEntityKey friendEntityKey = searchResult.friends[k];
            /*...*/
        }
    }
}
else
{
    //...
}
```

## ロビー検索キー

カスタム検索プロパティを定義する際には、制限された一連のキーのみを使用できます。

* 文字列プロパティの場合、次のキーがサポートされます: string\_key1、string\_key2、\[...] string\_key30
* 数値プロパティの場合、次のキーがサポートされます: number\_key1、number\_key2、\[...] number\_key30

## ロビー検索演算子

**FindLobbies** API のクエリ文字列は、OData に似た構文で構造化されます。フィルター文字列の最大サイズは 600 文字です。

これらの OData 演算子を使用してクエリ文字列を構成できます。演算子は大文字と小文字が区別されます。

| 演算子 | 意味    | 例                                                       |
| --- | ----- | ------------------------------------------------------- |
| eq  | 等しい   | string\_key1 eq 'CaptureTheFlag'                        |
| lt  | 未満    | number\_key2 lt 10                                      |
| le  | 以下    | number\_key2 le 10                                      |
| gt  | より大きい | number\_key3 gt 100                                     |
| ge  | 以上    | number\_key3 ge 100                                     |
| ne  | 等しくない | string\_key1 ne 'CaptureTheFlag'                        |
| and | かつ    | string\_key1 eq 'CaptureTheFlag' and number\_key2 lt 10 |

<Note>文字列プロパティを比較する場合は、比較する値を必ず一重引用符で囲んでください。たとえば、"string\_key1 eq **'SOME STRING VALUE'**" のようにします。数値プロパティは囲む必要はありません。</Note>

使用可能な事前定義済みの演算子もあります。指定する際には "lobby/" を前に付ける必要があります。

| 演算子                  | 意味                                             | 例                                  |
| -------------------- | ---------------------------------------------- | ---------------------------------- |
| memberCount          | ロビー内のプレイヤー数                                    | lobby/memberCount eq 5             |
| maxMemberCount       | ロビー内で許可されるプレイヤーの最大数                            | lobby/maxMemberCount gt 10         |
| memberCountRemaining | ロビーに参加可能なプレイヤーの残り数                             | lobby/memberCountRemaining gt 0    |
| membershipLock       | ロビーのロック状態。'Unlocked' または 'Locked' と等しくなければならない | lobby/membershipLock eq 'Unlocked' |
| amOwner              | 自分がオーナーであるロビー。'true' と等しくなければならない              | lobby/amOwner eq 'true'            |
| amMember             | 自分がメンバーであるロビー。'true' と等しくなければならない              | lobby/amMember eq 'true'           |
| amServer             | サーバーがクライアント所有のロビーに参加したロビー。'true' と等しくなければならない  | lobby/amServer eq 'true'           |

## 検索結果の並べ替え

このクエリの並べ替えを昇順 ("asc") または降順 ("desc") で含む OData スタイルの文字列。OrderBy 句は、任意の検索数値キーまたは数値の事前定義検索キーに使用できます。特定の数値に最も近い順に並べ替えるには、距離モニカーを使用して指定された数値検索キーからの距離で並べ替えることができます。距離ソートで昇順または降順を使用することはできません。このフィールドは、1 つのソート句または 1 つの距離句のみをサポートします。ソートが指定されていない場合、または指定されたソートに対してタイブレイクが必要な場合、デフォルトのソートは作成時刻に基づく降順になります。

| 例                          | 意味               |
| -------------------------- | ---------------- |
| number\_key1 asc           | 数値検索キーの昇順        |
| lobby/memberCount desc     | 数値検索キーの降順        |
| distance(number\_key1 = 5) | 指定された数値からの距離でソート |
|                            | 作成時刻の降順          |

### 検索結果の並べ替えとフィルタリング - サンプルコード

```cpp theme={null}
PFLobbySearchConfiguration searchConfiguration{};​
​
PFLobbySearchFriendsFilter friendsFilter{};    ​
friendsFilter.includeXboxFriendsToken = MyGame::GetLocalUserXboxToken();​
searchConfiguration.friendsFilter = &friendsFilter;​

// Create filter string for ranked deathmatch with skill between 10-20​
std::string filterString;​
filterString +=  "string_key1 eq DeathMatch and ";​ 
filterString +=  "string_key2 eq Ranked and ";​
filterString +=  "number_key1 -ge 10 and ";​
filterString +=  "number_key1 -le 20";​
​
// Create sort string based on skill level​
std::string sortString;​
sortString += std::string("distance{number_key1=" + std::to_string(playerSkill.c_str()) + "}";​

searchConfiguration.filterString = filterString.c_str();​
searchConfiguration.sortString = sortString.c_str();​
searchConfiguration.clientSearchResultCount = 10;        // limits the number of results​
```

## ロビーへの参加

次の表は、セッション/ロビーへの参加のために MPSD および PlayFab Multiplayer で使用される類似の関数のリストを示しています。

| MPSD                                                | PlayFab Multiplayer      |
| --------------------------------------------------- | ------------------------ |
| `XblMultiplayerGetSessionByHandleAsync`             | `PFMultiplayerJoinLobby` |
| `XblMultiplayerSessionJoin`                         |                          |
| `XblMultiplayerAddSessionChangedHandler`            |                          |
| `XblMultiplayerSessionSetSessionChangeSubscription` |                          |
| `XblMultiplayerSessionCurrentUserSetStatus`         |                          |
| `XblMultiplayerWriteSessionByHandleAsync`           |                          |
| `XblMultiplayerSessionCloseHandle`                  |                          |

<Note>ロビーに参加するには接続文字列が必要です。通常、ロビーのホストは自身のアクティビティにこの接続文字列を設定するか、招待経由で送信します。接続文字列を取得するには `PFLobbyGetConnectionString` を呼び出す必要があります。</Note>

### ロビーへの参加 - サンプルコード

初期参加構成を設定してから、ロビーに参加します。

```cpp theme={null}
const char* memberPropertyKeys[] { "number", "name"};
const char* memberPropertyValues[] { "8675309", "Jenny"};

PFLobbyJoinConfiguration joinConfig{};
joinConfig.memberPropertyCount = 2;
joinConfig.memberPropertyKeys = memberPropertyKeys;
joinConfig.memberPropertyValues = memberPropertyValues;

PFLobbyHandle myLobby{};

HRESULT hr = PFMultiplayerJoinLobby(
    pfmHandle,             // PFMultiplayerHandle
    &localUserEntityKey,   // local user
    lobbyConnectionString, // connection string
    &joinConfig,           // join config
    nullptr,               // async context (optional)
    &myLobby);             // handle to the lobby

if (FAILED(hr))
{
    //...
} 
```

## ロビーの更新

次の表は、セッション/ロビーの更新のために MPSD および PlayFab Multiplayer で使用される類似の関数のリストを示しています。

| MPSD                                      | PlayFab Multiplayer |
| ----------------------------------------- | ------------------- |
| `XblMultiplayerGetSessionByHandleAsync`   | `PFLobbyPostUpdate` |
| `XblMultiplayerWriteSessionByHandleAsync` |                     |
| `XblMultiplayerSessionCloseHandle`        |                     |

<Note>`PFLobbyPostUpdate` を使用して、ロビープロパティとメンバープロパティの両方を更新できます。関数を 1 回呼び出すことで、1 種類または両方の種類のプロパティを更新できます。</Note>

### ロビーの更新 - サンプルコード (ロビープロパティ)

```cpp theme={null}
const char* lobbyPropertyKeys[] { "exampleKey_1", "exampleKey_2" };
const char* lobbyPropertyValues[] { "exampleValue_1234", "exampleValue_ABCD" };

PFLobbyDataUpdate lobbyUpdateData{};
lobbyUpdateData.lobbyPropertyCount = 2;
lobbyUpdateData.lobbyPropertyKeys = lobbyPropertyKeys;
lobbyUpdateData.lobbyPropertyValues = lobbyPropertyValues;

HRESULT hr = PFLobbyPostUpdate(
    myLobby,             // handle to the lobby
    &localUserEntityKey, // local user
    &lobbyUpdateData,    // update data for the lobby
    nullptr,             // update data for a member
    nullptr);            // async context (optional)

if (FAILED(hr))
{
    //...
} 
```

### ロビーの更新 - サンプルコード (メンバープロパティ)

```cpp theme={null}
const char* memberPropertyKeys[] { "favoriteColor" };
const char* memberPropertyValues[] { "yellow" };

PFLobbyMemberDataUpdate memberUpdateData{};
memberUpdateData.lobbyPropertyCount = 1;
memberUpdateData.lobbyPropertyKeys = memberPropertyKeys;
memberUpdateData.lobbyPropertyValues = memberPropertyKeys;

HRESULT hr = PFLobbyPostUpdate(
    myLobby,             // handle to the lobby
    &localUserEntityKey, // local user
    nullptr,             // update data for the lobby
    & memberUpdateData   // update data for a member
    nullptr);            // async context (optional)

if (FAILED(hr))
{
    //...
}
```

## マッチメーキング

PlayFab Multiplayer のマッチメーキング API は、MPSD のマッチメーキング API と比較的類似しています。

| MPSD                              | PlayFab Multiplayer               |
| --------------------------------- | --------------------------------- |
| Smartmatch Hoppers を介した構成         | マッチメーキングキューに基づく                   |
| Hopper は MPSD セッションテンプレートにバインドされる | マッチメーキングルールはキューに適用される             |
| マッチメーキングルールは Hopper に適用される        | マッチメーキングはマッチチケットを介して開始される         |
| マッチメーキングには既存の MPSD セッションが必要       | マッチメーキングの結果は新しい PlayFab ロビー       |
| マッチメーキングの結果は新しい MPSD セッション        | PlayFab Multiplayer サーバー割り当てをサポート |

<Note>マッチメーキングキューは PlayFab Game Manager を介して構成する必要があります。</Note>

## マッチメーキングの状態変更

次の表は、マッチメーキングに関連するイベントを処理するために MPSD および PlayFab Multiplayer で使用される類似の関数のリストを示しています。

| MPSD                                           | PlayFab Multiplayer                                    |
| ---------------------------------------------- | ------------------------------------------------------ |
| `XblMultiplayerSessionSubscribedChangeTypes`   | `PFMultiplayerStartProcessingMatchmakingStateChanges`  |
| `XblMultiplayerSessionChangedHandler`          | `PFMultiplayerFinishProcessingMatchmakingStateChanges` |
| `XblMultiplayerSessionSubscriptionLostHandler` |                                                        |

### マッチメーキングの状態変更 - サンプルコード

状態変更の処理を開始することをライブラリに通知します。キューに入れられた各状態変更を処理してから、状態変更の処理が完了したことを通知します。

```cpp theme={null}
uint32_t stateChangeCount = 0;
const PFMatchmakingStateChange* const* stateChanges = nullptr;

HRESULT hr = PFMultiplayerStartProcessingMatchmakingStateChanges(pfmHandle, &stateChangeCount, &stateChanges);
if (FAILED(hr))
{
    //...
}

for (uint32 i = 0; i < stateChangeCount; ++i)
{
    const PFMatchmakingStateChange& change = *stateChanges[i];
    
    switch (change.stateChangeType)
    {
    case PFMatchmakingStateChangeType::TicketStatusChanged: /*...*/ break;
    case PFMatchmakingStateChangeType::TicketCompleted:     /*...*/ break;
    }
}

hr = PFMultiplayerFinishProcessingMatchmakingStateChanges(pfmHandle, stateChangeCount, stateChanges);
if (FAILED(hr))
{
    //...
}
```

## マッチメーキングの開始

| MPSD                                     | PlayFab Multiplayer                        |
| ---------------------------------------- | ------------------------------------------ |
| MPSD セッションの作成呼び出し...                     | `PFMultiplayerCreateMatchmakingTicket`     |
| `XblMatchmakingCreateMatchTicketAsync`   | `PFMultiplayerJoinMatchmakingTicketFromId` |
| `XblMatchmakingCreateMatchTicketResult`  | `PFMatchmakingTicketGetStatus`             |
| `XblMultiplayerSessionMatchmakingServer` | `PFMatchmakingTicketGetMatch`              |
| MPSD セッションへの参加呼び出し...                    | `PFMultiplayerJoinArrangedLobby`           |

### マッチメーキングの開始 - サンプルコード

```cpp theme={null}
PFMatchmakingTicketConfiguration matchTicketConfig{};
matchTicketConfig.timeoutInSeconds;        // how long to attempt matchmaking
matchTicketConfig.queueName;               // matchmaking queue name
matchTicketConfig.membersToMatchWithCount; // num remote players to go into matchmaking with
matchTicketConfig.membersToMatchWith;      // remote players to go into matchmaking with

HRESULT hr = PFMultiplayerCreateMatchmakingTicket(
    pfmHandle,                   // PFMultiplayerHandle
    1,                           // local user count
    &currentUserEntityKey,       // local users
    nullptr,                     // local user attributes (optional)
    &ticketConfig,               // ticket config
    nullptr,                     // async context (optional)
    &m_activeMatchmakingTicket); // matchmaking ticket

if (FAILED(hr))
{
    //...
} 

hr = PFMultiplayerJoinMatchmakingTicketFromId(
    pfmHandle,                   // PFMultiplayerHandle
    1,                           // local user count
    &currentUserEntityKey,       // local users
    nullptr,                     // local user attributes (optional)
    ticketId,                    // matchmaking ticket to join
    queueName,                   // matchmaking queue name
    nullptr,                     // async context (optional)
    &m_activeMatchmakingTicket); // matchmaking ticket

if (FAILED(hr))
{
    //...
}
```

<Note>マッチメーキングは、`membersToMatchWith` フィールドに指定されたすべてのメンバーが参加するまで開始されません。</Note>

次に、マッチが見つかり、状態変更が返されたら、arranged lobby に参加します。

```cpp theme={null}
const auto& stateChange = static_cast<const PFMatchmakingTicketCompletedStateChange&>(change);
if (SUCCEEDED(stateChange.result))
{
    PFMatchmakingTicketStatus status{};
    HRESULT hr = PFMatchmakingTicketGetStatus(stateChange.ticket, &status);
    if (SUCCEEDED(hr))
    {
        if (status == PFMatchmakingTicketStatus::Matched)
        {
            const PFMatchmakingMatchDetails* matchDetails = nullptr;
            hr = PFMatchmakingTicketGetMatch(stateChange.ticket, &matchDetails);
            if (SUCCEEDED(hr))
            {
                const char* memberPropertyKeys[] { "favoriteCheese" };
                const char* memberPropertyValues[] { "Wensleydale" };

                PFLobbyArrangedJoinConfiguration joinConfig{};
                joinConfig.accessPolicy = PFLobbyAccessPolicy::Private;
                joinConfig.maxMemberCount = 4;
                joinConfig.ownerMigrationPolicy = PFLobbyOwnerMigrationPolicy::Automatic;
                joinConfig.memberPropertyCount = 1;
                joinConfig.memberPropertyKeys = memberPropertyKeys;
                joinConfig.memberPropertyValues = memberPropertyValues;
                
                PFLobbyHandle myLobby{};

                hr = PFMultiplayerJoinArrangedLobby(
                    pfmHandle,                            // PFMultiplayerHandle
                    &localUserEntityKey,                  // local user
                    matchDetails->lobbyArrangementString, // connection string
                    &config,                              // join config
                    nullptr,                              // async context (optional)
                    &myLobby);                            // handle to the lobby

                if (FAILED(hr))
                {
                    //...
                }
            }
        }
    }
}
```

## クリーンアップ

次の表は、クリーンアップとシャットダウンのために MPSD および PlayFab Multiplayer で使用される類似の関数のリストを示しています。

| MPSD                                             | MPA                         |
| ------------------------------------------------ | --------------------------- |
| `XblMultiplayerRemoveSubscriptionLostHandler`    | `PFMultiplayerUninitialize` |
| `XblMultiplayerRemoveConnectionIdChangedHandler` |                             |
| `XblMultiplayerSetSubscriptionsEnabled`          |                             |

<Note>`PFMultiplayerUninitialize` を呼び出す前に、必ずすべてのアクティブなロビーから離脱し、進行中のマッチメーキングチケットを破棄してください。</Note>

### クリーンアップ - サンプルコード

```cpp theme={null}
HRESULT hr = PFMultiplayerUninitialize(pfmHandle);
if (FAILED(hr))
{
    //...
}
```

## アクティビティ

次の表は、アクティビティを管理するために MPSD および MPA で使用される類似の関数のリストを示しています。

| MPSD                               | MPA                                           |
| ---------------------------------- | --------------------------------------------- |
| `XblMultiplayerSetActivityAsync`   | `XblMultiplayerActivitySetActivityAsync`      |
| `XblMultiplayerClearActivityAsync` | `XblMultiplayerActivityDeleteActivityAsync`   |
|                                    | `XblMultiplayerActivityGetActivityAsync`      |
|                                    | `XblMultiplayerActivityGetActivityResultSize` |
|                                    | `XblMultiplayerActivityGetActivityResult`     |

<Note>アクティビティを設定したり招待を送信したりする場合は、必ず `PFLobbyGetConnectionString` から返される接続文字列を使用してください。</Note>

### アクティビティ - サンプルコード

```cpp theme={null}
const char* connectionString;
HRESULT hr = PFLobbyGetConnectionString(myLobby, &connectionString);
if (FAILED(hr))
{
    //...
}

uint32_t maxPlayerCount;
hr = PFLobbyGetMaxMemberCount(myLobby, &maxPlayerCount);
if (FAILED(hr))
{
    //...
}

uint32_t lobbyMemberCount;
const PFEntityKey* lobbyMembers;
hr = PFLobbyGetMembers(myLobby, &lobbyMemberCount, &lobbyMembers);
if (FAILED(hr))
{
    //...
}

const char* lobbyId;
hr = PFLobbyGetLobbyId(myLobby, &lobbyId);
if (FAILED(hr))
{
    //...
}

PFLobbyAccessPolicy pfAccessPolicy;
hr = PFLobbyGetAccessPolicy(LobbyHandle, &pfAccessPolicy);
if (FAILED(hr))
{
    //...
}

XblMultiplayerActivityJoinRestriction joinRestriction = XblMultiplayerActivityJoinRestriction::InviteOnly;

switch (pfAccessPolicy)
{
case PFLobbyAccessPolicy::Public:  joinRestriction = XblMultiplayerActivityJoinRestriction::Public; break;
case PFLobbyAccessPolicy::Friends: joinRestriction = XblMultiplayerActivityJoinRestriction::Followed; break;
case PFLobbyAccessPolicy::Private: joinRestriction = XblMultiplayerActivityJoinRestriction::InviteOnly; break;
}

XblMultiplayerActivityInfo info{};
info.connectionString = connectionString;
info.joinRestriction = joinRestriction;
info.maxPlayers = maxPlayerCount;
info.currentPlayers = lobbyMemberCount;
info.groupId = lobbyId;
info.xuid = myXuid;

auto async = std::make_unique<XAsyncBlock>();
async->queue = queue;
async->callback = [](XAsyncBlock* async) 
{
    std::unique_ptr<XAsyncBlock> asyncBlockPtr{ async };
    HRESULT hr = XAsyncGetStatus(async, false);
    if(FAILED(hr))
    {
        //...
    }
};

HRESULT hr = XblMultiplayerActivitySetActivityAsync(
    xblContext,    // XblContextHandle
    &info,         // XblMultiplayerActivityInfo
    false,         // Allow cross-platform joins
    async.get()    // XAsyncBlock
);

if (SUCCEEDED(hr)) 
{
    async.release();
}
else
{
    //...
}
```

## 招待

次の表は、招待を送受信するために MPSD および MPA で使用される類似の関数のリストを示しています。

| MPSD                             | MPA                                             |
| -------------------------------- | ----------------------------------------------- |
| `XGameInviteRegisterForEvent`    | `XGameInviteRegisterForEvent`                   |
| `XGameInviteUnregisterForEvent`  | `XGameInviteUnregisterForEvent`                 |
| `XblMultiplayerSendInvitesAsync` | `XblMultiplayerActivitySendInvitesAsync`        |
| `XGameUiShowSendGameInviteAsync` | `XGameUiShowMultiplayerActivityGameInviteAsync` |

### 招待 - サンプルコード (タイトル UI)

```cpp theme={null}
const char* connectionString;
HRESULT hr = PFLobbyGetConnectionString(myLobby, &connectionString);
if (SUCCEEDED(hr))
{
    auto async = std::make_unique<XAsyncBlock>();
    async->queue = queue;
    async->callback = [](XAsyncBlock* async)
    {
        std::unique_ptr<XAsyncBlock> asyncBlockPtr{ async };
        HRESULT hr = XAsyncGetStatus(async, false);
        if(FAILED(hr))
        {
            //...   
        }
    };
    
    HRESULT hr = XblMultiplayerActivitySendInvitesAsync(
        xblContext,       // XblContextHandle 
        &xuid,            // recipient
        1,                // number of invited XUIDs
        true,             // allow cross-platform joins
        connectionString, // use lobby connection string
        async.get());

    if (SUCCEEDED(hr))
    {
        async.release();
    }
    else
    {
        //...
    }
}
else
{
    //...
}
```

### 招待 - サンプルコード (XBOX UI)

```cpp theme={null}
auto async = std::make_unique<XAsyncBlock>();
async->queue = queue;
async->callback = [](XAsyncBlock* async)
{
    std::unique_ptr<XAsyncBlock> async{ async };
    HRESULT hr = XGameUiShowMultiplayerActivityGameInviteResult(async);
    if(FAILED(hr))
    {
        //...   
    }
};

HRESULT hr = XGameUiShowMultiplayerActivityGameInviteAsync(
    async.get(), // XAsyncBlock
    user.get()   // XUserHandle that is sending the invite
);

if (SUCCEEDED(hr))
{
    async.release();
}
else
{
    //...
}
```

<Note>`XGameUiShowMultiplayerActivityGameInviteResult` は現在設定されているアクティビティを使用します。この関数を使用する前に、`XblMultiplayerActivitySetActivityAsync` を使用してアクティビティを設定する必要があります。</Note>

## 最近のプレイヤー

次の表は、MPSD および MPA を使用する際の最近のプレイヤーリストの管理方法を示しています。

| MPSD                                   | MPA                                             |
| -------------------------------------- | ----------------------------------------------- |
| プレイヤーは同じ MPSD セッションにいる必要がある            | `XblMultiplayerActivityUpdateRecentPlayers`     |
| セッションの `gameplay` プロパティが `true` に設定される | `XblMultiplayerActivityFlushRecentPlayersAsync` |
| 両方のプレイヤーがアクティブとしてマークされる                |                                                 |

<Note>スロットリングを避けるため、`XblMultiplayerActivityUpdateRecentPlayers` への呼び出しをバッチ処理することがベストプラクティスです。</Note>

### 最近のプレイヤー - サンプルコード

```cpp theme={null}
XblMultiplayerActivityRecentPlayerUpdate update{};
update.xuid = metPlayerXuid;
update.encounterType = XblMultiplayerActivityEncounterType::Default;

HRESULT hr = XblMultiplayerActivityUpdateRecentPlayers(xblContext, &update, 1);
if (FAILED(hr))
{
    //...
}
```


## Related topics

- [PlayFab スタンドアロン SDK v1 から統合 SDK v2 への移行](/ja-jp/services/playfab/sdks/unified-sdk/migrating-from-v1.md)
- [XDK ネットワークから XBOX GDK への移行](/ja-jp/build/console-features/networking/xdk-migration/index.md)
- [XBOX GDK への移植ガイド](/ja-jp/home/build-first-title/porting-guides.md)
- [概念](/ja-jp/services/xbox-services/multiplayer/mpsd/concepts/index.md)
- [Google サインインから Play Games サインインへの移行フォールバック](/ja-jp/services/playfab/identity/player-identity/platform-specific-authentication/google-play-games-sign-in-migration-fallback.md)
