> ## 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 Party を使用する

> PlayFab Party の音声およびデータネットワーキングを、XBOX Multiplayer Session Directory (MPSD) と組み合わせて、クロスネットワークのセッション管理と招待を実現します。

XBOX のマルチプレイヤーシナリオは、Multiplayer Session Directory (MPSD) サービスと MPSD ドキュメントの使用に依存しています。MPSD ドキュメントは現在のゲームセッションの名簿として機能し、マッチメイキング、プラットフォーム招待、最近のプレイヤーリスト、ジョインインプログレスなどのマルチプレイヤー体験を支えます。

このドキュメントでは、MPSD を必要とする一般的なマルチプレイヤーフローに PlayFab Party を組み込む方法を説明します。

このドキュメントでは、MPSD とそのすべての機能について詳しく説明することはしません。詳細については、[MPSD のドキュメント](/services/xbox-services/multiplayer/mpsd/live-mpsd-overview) を参照してください。

## マッチメイキング

以下は、PlayFab Party と共にマッチメイキングと MPSD を使用する簡略化されたフローです。

1. プレイヤーは、マッチメイキングセッションをまたいで一緒にプレイしたいグループを表す MPSD セッションを作成し、そこに集まります。プレイヤーは XBOX の招待および参加機能を使用してこれらのセッションに集まります。

2. これらのプレイヤーグループはマッチメイキングサービスにチケットを送信し、互換性のあるプレイヤーグループがマッチメイキングセッションにまとめられます。このマッチメイキングセッション自体は、新しいセッションドキュメントで表され、その後プレイヤーが参加します。プレイヤーはまた、このセッションドキュメントの変更を監視する必要があります。

3. マッチメイキングセッションが確定し、名簿がロックされたら、タイトルは PlayFab Party ネットワークをセットアップするマッチメイキングセッションのメンバーのうち 1 人を選出する必要があります。Party ネットワーク作成者を選択するシンプルな戦略は、マッチメイキング MPSD セッションドキュメントの最初のメンバーを使用することです。

4. 選出されたメンバーは、マッチメイキングセッションのメンバーのみにネットワークアクセスを制限する初期 `PartyInvitation` を使用してネットワークを作成します。ネットワークの作成が正常に完了したら、選出されたメンバーは結果のネットワーク記述子と Party 招待をセッションドキュメントにセッションプロパティとして投稿し、他のメンバーが使用できるようにする必要があります。

   ```cpp theme={null}
   void
   OnMatchmakingSessionFinalized(
       uint32_t usersInSessionCount,
       const uint64_t* usersInSession
       )
   {
       PartyInvitationConfiguration initialInvite{};
       initialInvite.identifier = nullptr; // let Party select the invitation identifier for simplicity
       initialInvite.revocability = PartyInvitationRevocability::Anyone; // must be revocable by anyone

       // the updated invite should contain all users in the matchmaking session
       std::vector<PartyString> entityIdsInSession;
       for (uint32_t i = 0; i < usersInSessionCount; ++i)
       {
           uint64_t xboxUserId = usersInSession[i];
           // Call title-defined xuid->entityid mapping helper
           PartyString xboxUserEntityId = GetEntityIdFromXboxUserId(xboxUserId);
           if (xboxUserEntityId != nullptr)
           {
               entityIdsInSession.push_back(xboxUserEntityId);
           }
           else
           {
               DEBUGLOG("User %llu did not have a matching entity ID.", xboxUserId);
           }
       }
       initialInvite.entityIdCount = entityIdsInSession.size();
       initialInvite.entityIds = entityIdsInSession.data();

       // This is an asynchronous call. It will be completed when StartProcessingStateChanges generates a
       // PartyCreateNewNetworkCompletedStateChange struct
       PartyError error = PartyManager::GetSingleton().CreateNewNetwork(
           m_localPartyUser,
           &networkConfiguration,
           0,
           nullptr,
           &initialInvite,
           nullptr,
           nullptr,
           nullptr);
       if (FAILED(error))
       {
           DEBUGLOG("PartyManager::CreateNetwork failed! 0x%08x\n", error);
           return;
       }
   }

   void
   HandleCreateNewNetworkCompleted(
       const PartyCreateNewNetworkCompletedStateChange& createNewNetworkCompletedStateChange
       )
   {
       if (createNewNetworkCompletedStateChange.result == PartyStateChangeResult::Succeeded)
       {
           // The network was created successfully! Post the networks descriptor and invitation

           char serializedDescriptor[c_maxSerializedNetworkDescriptorStringLength + 1];
           PartyError error = PartyManager::SerializeNetworkDescriptor(
               &createNewNetworkCompletedStateChange.networkDescriptor,
               serializedDescriptor);
           if (PARTY_FAILED(error))
           {
               DEBUGLOG("PartyManager::SerializeNetworkDescriptor failed: 0x%08x\n", error);
               return;
           }

           UpdateSessionProperty(
               "PartyNetworkDescriptor", // arbitrary property name
               serializedDescriptor);

           UpdateSessionProperty(
               "PartyInitialInvitation", // arbitrary property name
               createNewNetworkCompletedStateChange.appliedInitialInvitationIdentifier);
       }
       else
       {
           // The network was not created successfully.
           // Please refer to CreateNewNetwork reference documentation for retry guidance
       }
   }
   ```

5. 各メンバーはセッションドキュメントの更新を確認したら、ネットワーク記述子と招待を使用してネットワークに接続し、参加できます。

   ```cpp theme={null}
   void
   OnNetworkInformationPostedToSessionDocument(
       PartyString serializedNetworkDescriptor,
       PartyString invitationId
       )
   {
       PartyNetworkDescriptor networkDescriptor;
       PartyError error = PartyManager::DeserializeNetworkDescriptor(serializedNetworkDescriptor, &networkDescriptor);
       if (PARTY_FAILED(error))
       {
           DEBUGLOG("PartyManager::DeserializeNetworkDescriptor failed: 0x%08x\n", error);
           return;
       }

       // attempt to connect to the network
       PartyNetwork* network;
       error = PartyManager::GetSingleton().ConnectToNetwork(
           &networkDescriptor,
           nullptr,
           &network);
       if (PARTY_FAILED(error))
       {
           DEBUGLOG("PartyManager::ConnectToNetwork failed: 0x%08x\n", error);
           return;
       }

       // immediately queue an authentication on the network we've attempted to connect to.
       error = network->AuthenticateLocalUser(
           m_localUser,
           invitationId,
           nullptr);
       if (PARTY_FAILED(error))
       {
           DEBUGLOG("PartyNetwork::AuthenticateLocalUser failed: 0x%08x\n", error);
           return;
       }
   }
   ```

<Note>
  ここでは、マッチメイキングと MPSD を PlayFab Party に組み込む 1 つのフローを示しました。このフローの中核となる考え方は、MPSD で検討したい他のフローにも拡張できますが、すべての可能なフローを提示することはこのドキュメントの範囲外です。詳細については、[MPSD の完全なドキュメント](https://learn.microsoft.com/en-us/gaming/gdk/_content/gc/live/get-started/live-xbl-overview) を参照してください。
</Note>

## プラットフォーム招待

以下は、XBOX プラットフォームの招待を PlayFab Party に組み込むフローです。

1. *PlayerA* が MPSD セッションドキュメントを作成し、セッションの変更を監視し、Party ネットワークを作成します。Party ネットワークの作成が完了したら、*PlayerA* はネットワーク記述子と初期招待（必要な場合）を MPSD セッションドキュメントに投稿します。

   ```cpp theme={null}
   void
   OnSessionDocumentCreated()
   {
       // This is an asynchronous call. It will be completed when StartProcessingStateChanges generates a
       // PartyCreateNewNetworkCompletedStateChange struct
       PartyError error = PartyManager::GetSingleton().CreateNewNetwork(
           m_localPartyUser,
           &networkConfiguration,
           0,
           nullptr,
           nullptr,
           nullptr,
           nullptr,
           nullptr);
       if (FAILED(error))
       {
           DEBUGLOG("PartyManager::CreateNetwork failed! 0x%08x\n", error);
           return;
       }
   }

   void
   HandleCreateNewNetworkCompleted(
       const PartyCreateNewNetworkCompletedStateChange& createNewNetworkCompletedStateChange
       )
   {
       if (createNewNetworkCompletedStateChange.result == PartyStateChangeResult::Succeeded)
       {
           // The network was created successfully! Post the networks descriptor and invitation

           char serializedDescriptor[c_maxSerializedNetworkDescriptorStringLength + 1];
           PartyError error = PartyManager::SerializeNetworkDescriptor(
               &createNewNetworkCompletedStateChange.networkDescriptor,
               serializedDescriptor);
           if (PARTY_FAILED(error))
           {
               DEBUGLOG("PartyManager::SerializeNetworkDescriptor failed: 0x%08x\n", error);
               return;
           }

           UpdateSessionProperty(
               "PartyNetworkDescriptor", // arbitrary property name
               serializedDescriptor);
       }
       else
       {
           // The network was not created successfully.
           // Please refer to CreateNewNetwork reference documentation for retry guidance
       }
   }
   ```

2. *PlayerA* が *PlayerB* を Party ネットワークに招待したい場合、*PlayerA* はゲーム内またはコンソール UI 経由でプラットフォーム招待を *PlayerB* に開始します。

3. *PlayerB* は、*PlayerA* の MPSD セッションドキュメントを検索するために使用できる「招待ハンドル」を含むプラットフォーム招待を受け取ります。

4. *PlayerB* はセッションドキュメントに参加し、変更を監視します。

5. *PlayerA* は *PlayerB* がセッションドキュメントに参加したことを確認します。*PlayerA* は *PlayerB* が使用するための新しい招待を作成し、その招待をセッションドキュメントに投稿します

   ```cpp theme={null}
   void
   OnUserJoinedSessionDocument(
       PartyNetwork* network,
       uint64_t newSessionMemberXboxUserId
       )
   {
       std::string newMemberIdString = std::to_string(newSessionMemberXboxUserId);

       // Specify our own invitation id so we don't have to query for it after the invitation has been created.
       // Here we will specify the invite id with the format "InviterXboxUserID_InviteeXboxUserID" so that we can
       // ensure this invitation ID doesn't clash with the invitations other members might try and create for this user.
       std::string invitationId = std::to_string(m_localXboxUserId) + "_" + newMemberIdString;

       PartyInvitationConfiguration newInvite{};
       newInvite.identifier = invitationId.c_str();
       newInvite.revocability = PartyInvitationRevocability::Creator; // must be revocable by the creator only

       // Call title-defined xuid->entityid mapping helper
       PartyString newSessionMemberEntityId = GetEntityIdFromXboxUserId(newSessionMemberXboxUserId);
       newInvite.entityIdCount = 1;
       newInvite.entityIds = &newSessionMemberEntityId;

       // Create a new invitation which includes all of the users currently in the document
       PartyInvitation* newInvitation;
       PartyError error = network->CreateInvitation(
           m_localUser,
           &newInvite,
           nullptr,
           &newInvitation);
       if (PARTY_FAILED(error))
       {
           DEBUGLOG("PartyNetwork(0x%p)::CreateInvitation failed! (error=0x%x)", network, error);
           return;
       }

       // Post the invitation to the local user's member property store in the session document, key'd by the invitee's
       // xbox user id. This will let the invitee recognize when an invitation is intended for them.
       UpdateMemberProperty(
           newMemberIdString.c_str(),
           invitationId.c_str());
   }
   ```

6. *PlayerB* はセッションドキュメントに投稿された招待を確認し、それを使用して Party ネットワークに参加します。

   ```cpp theme={null}
   void
   OnRemoteMemberPropertyUpdated(
       PartyString memberPropertyKey,
       PartyString memberPropertyValue
       )
   {
       // The member property update signifies a new invitation, if the remote member updated a property that matches
       // our xbox user id.
       if (memberPropertyKey == std::to_string(m_localXboxUserId))
       {
           OnUserInvitationPostedToSessionDocument(memberPropertyValue);
       }

       // ...
   }

   void
   OnUserInvitationPostedToSessionDocument(
       PartyString invitationId
       )
   {
       // The network descriptor should have already been posted to the session document before the invitation.
       // Call title-defined function to pull it from the session document.
       PartyNetworkDescriptor networkDescriptor = QueryNetworkDescriptorFromSessionDocument();

       // attempt to connect to the network
       PartyNetwork* network;
       error = PartyManager::GetSingleton().ConnectToNetwork(
           &networkDescriptor,
           nullptr,
           &network);
       if (PARTY_FAILED(error))
       {
           DEBUGLOG("PartyManager::ConnectToNetwork failed: 0x%08x\n", error);
           return;
       }

       // immediately queue an authentication on the network we've attempted to connect to.
       error = network->AuthenticateLocalUser(
           m_localUser,
           invitationId,
           nullptr);
       if (PARTY_FAILED(error))
       {
           DEBUGLOG("PartyNetwork::AuthenticateLocalUser failed: 0x%08x\n", error);
           return;
       }
   }
   ```

<Info>
  [PartyNetwork::CreateInvitation](/services/playfab/multiplayer/networking/reference/classes/PartyNetwork/methods/partynetwork_createinvitation) 経由で作成された招待は、それを作成した PartyLocalUser がネットワークを離れると無効になります。したがって、新しいユーザーがセッションドキュメントに自身を追加したものの、招待したユーザーがネットワークを離れた場合は、新しいユーザーはセッションドキュメントから自身を削除し、別のユーザーから再招待されるのを待つことをお勧めします。
</Info>

## ジョインインプログレス

進行中のゲームセッションへの参加は、[プラットフォーム招待](#platform-invites) のシナリオと非常によく似ています。中核となる違いは、*PlayerA* が *PlayerB* に「招待ハンドル」を送信する代わりに、*PlayerB* がプラットフォーム UI からジョインインプログレスを開始したときに「参加ハンドル」を取得することです。この「参加ハンドル」を使用して、*PlayerB* はセッションドキュメントに参加し、変更を監視します。*PlayerA* は、新しい Party 招待を作成してセッションドキュメントに投稿することでこれに応答します。*PlayerB* は、ネットワーク記述子と共にこの新しい招待を確認し、それを使用して Party ネットワークに参加します。

<Info>
  [PartyNetwork::CreateInvitation](/services/playfab/multiplayer/networking/reference/classes/PartyNetwork/methods/partynetwork_createinvitation) 経由で作成された招待は、それを作成した PartyLocalUser がネットワークを離れると無効になります。したがって、新しいユーザーがジョインインプログレスフローから Party 招待を受け取ったものの、それを作成したユーザーが離れているために使用できない場合、新しいユーザーはセッションドキュメントから自身を削除し、後で再参加することをお勧めします。これにより、セッションの別のメンバーがフローを再開し、このユーザー用に新しい Party 招待を生成できるようになります。
</Info>

## 切断とクリーンアップ

プレイヤーが Party ネットワークを離れる、または何らかの形で切断された場合、その Party ネットワークに関連付けられた MPSD セッションからも自身を削除する必要があります。[PartyNetwork::LeaveNetwork](/services/playfab/multiplayer/networking/reference/classes/PartyNetwork/methods/partynetwork_leavenetwork) 操作によって開始されない Party ネットワークの切断は、致命的とみなされます。致命的な切断を経験した後、プレイヤーはネットワークへの再接続と再認証を試みることができますが、MPSD セッションにも再参加する必要があります。

プレイヤーの MPSD セッションへの接続が一時的に中断された場合、そのセッションから切断される可能性があります。プレイヤーはセッションへの再参加を試みることができますが、失敗した場合は、[PartyNetwork::LeaveNetwork](/services/playfab/multiplayer/networking/reference/classes/PartyNetwork/methods/partynetwork_leavenetwork) を呼び出して自発的に Party ネットワークから離脱するべきです。

<Note>
  Party ネットワークと MPSD セッションの切断を検出するメカニズムとヒューリスティックは異なります。プレイヤーが Party ネットワークと MPSD セッションの両方から切断されるシナリオでも、これらの切断イベントは独立しており、時間的に近接して発生することは保証されません。タイトルは、プレイヤーが Party ネットワークまたは MPSD セッションのいずれか一方のみから切断される可能性があるシナリオを処理する必要があります。
</Note>

ゲームがシャットダウンすると、プレイヤーは Party ネットワークと MPSD ドキュメントから自動的に切断され、それ以上のクリーンアップは必要ありません。


## Related topics

- [Unity で GDK を使用する](/ja-jp/build/gdk-and-engines/unity/unity.md)
- [Unreal Engine で GDK を使用する](/ja-jp/build/gdk-and-engines/unreal/unreal.md)
- [Unity で Google Play Games サインインを使用した PlayFab 認証](/ja-jp/services/playfab/identity/player-identity/platform-specific-authentication/google-sign-in-unity.md)
- [Unity で Editor Extensions を使わずに PlayFab SDK をインストールする](/ja-jp/services/playfab/sdks/unity3d/installing-unity3d-sdk.md)
- [Godot で GDK を使用する](/ja-jp/build/gdk-and-engines/godot.md)
