> ## 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 다중 플레이어 세션 디렉터리(MPSD)와 결합합니다.

XBOX 멀티플레이어 시나리오는 다중 플레이어 세션 디렉터리(MPSD) 서비스와 MPSD 문서의 사용에 의존합니다. MPSD 문서는 현재 게임 세션의 명부 역할을 하며, 매치메이킹, 플랫폼 초대, 최근 플레이어 목록 및 참가 중 참여(join-in-progress)와 같은 멀티플레이어 경험을 구동합니다.

이 문서에서는 MPSD가 필요한 일반적인 멀티플레이어 흐름에 PlayFab Party를 통합하는 방법을 설명합니다.

이 문서는 MPSD와 그 모든 기능에 대한 심층적인 논의를 제공하지 않습니다. 자세한 내용은 [MPSD 설명서](/services/xbox-services/multiplayer/mpsd/live-mpsd-overview)를 참조하세요.

## 매치메이킹

다음은 PlayFab Party와 함께 매치메이킹과 MPSD를 사용하는 간소화된 흐름입니다:

1. 플레이어는 매치메이킹 세션 전반에 걸쳐 함께 플레이하려는 그룹을 나타내는 MPSD 세션을 만들고 모입니다. 플레이어는 XBOX의 초대 및 참가 기능을 사용하여 이러한 세션에 모입니다.

2. 이러한 플레이어 그룹은 매치메이킹 서비스에 티켓을 제출하고, 매치메이킹 서비스는 호환되는 플레이어 그룹을 매치메이킹 세션으로 모읍니다. 이 매치메이킹 세션 자체는 새로운 세션 문서로 표현되며, 그런 다음 플레이어가 참가합니다. 플레이어는 이 세션 문서의 변경 사항을 수신 대기해야 합니다.

3. 매치메이킹 세션이 완료되고 명부가 잠기면, 타이틀은 매치메이킹 세션의 멤버 중 한 명을 선택하여 PlayFab Party 네트워크를 설정해야 합니다. 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에 통합하는 하나의 흐름을 소개했습니다. 이 흐름의 핵심 아이디어는 관심 있는 다른 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>

## 참가 중 참여(Join in-progress)

진행 중인 게임 세션에 참여하는 것은 [플랫폼 초대](#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

- [XBOX 요구 사항](/ko/services/playfab/multiplayer/networking/xbox-requirements.md)
- [Kongregate와 Unity를 사용하여 PlayFab 인증 설정하기](/ko/services/playfab/identity/player-identity/platform-specific-authentication/kongregate-unity.md)
- [Kongregate와 HTML5를 사용하여 PlayFab 인증 설정하기](/ko/services/playfab/identity/player-identity/platform-specific-authentication/kongregate-html5.md)
- [Twitch와 HTML5를 사용하여 PlayFab 인증 설정하기](/ko/services/playfab/identity/player-identity/platform-specific-authentication/twitch-html5.md)
- [Google과 HTML5를 사용하여 PlayFab 인증 설정하기](/ko/services/playfab/identity/player-identity/platform-specific-authentication/google-html5.md)
