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

# Passer de MPSD à PlayFab Multiplayer et MPA

> Guide de migration des titres XBOX de MPSD vers les lobbies PlayFab Multiplayer et Multiplayer Activity (MPA) pour les invitations, le matchmaking et les joueurs récents.

## Introduction

Ce document s'adresse aux développeurs de jeux qui utilisent actuellement MPSD et souhaitent passer à PlayFab Multiplayer et MPA pour leurs jeux multijoueurs. Il couvre les scénarios multijoueurs les plus courants et fournit des extraits de code montrant comment utiliser PlayFab Multiplayer avec MPA.

### Vue d'ensemble de Multiplayer Session Directory (MPSD)

* Service de session complet permettant de partager les informations nécessaires pour connecter un groupe d'utilisateurs
* Intégré à l'interface utilisateur XBOX pour les fonctionnalités d'invitation et de jonction
* Entièrement intégré au matchmaking SmartMatch
* Les sessions sont dérivées de modèles de session prédéfinis
* Fonctionnalités intégrées de détection de la connectivité et de gestion du flux de session
* Disponible en service à service

### Vue d'ensemble du service Multiplayer Activity (MPA)

* Service léger qui simplifie l'intégration XBOX Live pour les activités des joueurs, les invitations et les joueurs récents
* Se coordonne avec le shell et le système d'exploitation de la console pour l'envoi et l'acceptation d'invitations et les jonctions
* Aucune gestion de session ni aucun matchmaking
* Disponible en service à service

### Vue d'ensemble de PlayFab Multiplayer

* Service complet de lobby multijoueur incluant des fonctionnalités de recherche et de parcours des lobbies
* Notifications de service multiplateformes en temps réel avec une intégration d'API transparente
* Service de matchmaking complet prenant en charge les notifications en temps réel

## Initialisation

Le tableau suivant répertorie les fonctions comparables utilisées par MPSD et PlayFab Multiplayer pour l'initialisation.

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

### Initialisation - Exemple de code

Initialisez la bibliothèque avec votre titleID PlayFab et définissez le jeton d'entité reçu lors de la connexion au service PlayFab.

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

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

## Modifications de l'état du lobby

Le tableau suivant répertorie les fonctions comparables utilisées par MPSD et PlayFab Multiplayer pour gérer les événements liés aux sessions et aux lobbies.

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

### Modifications de l'état du lobby - Exemple de code

Indiquez à la bibliothèque que vous commencez à traiter les modifications d'état. Traitez chaque modification d'état en file d'attente, puis indiquez que vous avez terminé de traiter les modifications d'état.

```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))
{
    //...
}
```

## Créer un lobby

Le tableau suivant répertorie les fonctions comparables utilisées par MPSD et PlayFab Multiplayer pour créer et rejoindre une session ou un lobby.

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

<Note>Aucune installation ni configuration supplémentaire dans PlayFab Game Manager n'est nécessaire pour créer un lobby. Toute la configuration peut être effectuée dans le code.</Note>

### Créer un lobby - Exemple de code

Configurez le lobby et définissez les éventuelles propriétés initiales du lobby ou des membres, puis créez et rejoignez le lobby.

```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))
{
    //...
}
```

## Rechercher des lobbies

Le tableau suivant répertorie les fonctions comparables utilisées par MPSD et PlayFab Multiplayer pour rechercher des sessions ou des lobbies.

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

### Rechercher des lobbies - Exemple de code

Définissez la configuration de recherche, puis recherchez des lobbies.

```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))
{
    //...
} 
```

Ensuite, une fois la modification d'état de l'événement renvoyée, traitez les résultats de la recherche.

```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
{
    //...
}
```

## Clés de recherche de lobby

Seul un ensemble restreint de clés peut être utilisé pour définir des propriétés de recherche personnalisées.

* Pour les propriétés de type chaîne, les clés suivantes sont prises en charge : string\_key1, string\_key2, \[...] string\_key30
* Pour les propriétés numériques, les clés suivantes sont prises en charge : number\_key1, number\_key2, \[...] number\_key30

## Opérateurs de recherche de lobby

Les chaînes de requête des API **FindLobbies** sont structurées selon une syntaxe de type OData. La taille maximale de la chaîne de filtre est de 600 caractères.

Ces opérateurs OData peuvent être utilisés pour composer des chaînes de requête. Les opérateurs sont sensibles à la casse.

| Opérateurs | Signification | Exemple |
| - | - | - |
| eq | égal à | string\_key1 eq 'CaptureTheFlag' |
| lt | inférieur à | number\_key2 lt 10 |
| le | inférieur ou égal à | number\_key2 le 10 |
| gt | supérieur à | number\_key3 gt 100 |
| ge | supérieur ou égal à | number\_key3 ge 100 |
| ne | différent de | string\_key1 ne 'CaptureTheFlag' |
| and | et | string\_key1 eq 'CaptureTheFlag' and number\_key2 lt 10 |

<Note>Lorsque vous comparez des propriétés de type chaîne, veillez à placer la valeur comparée entre apostrophes. Par exemple, "string\_key1 eq **'SOME STRING VALUE'**". Les propriétés numériques n'ont pas besoin d'être entourées d'apostrophes.</Note>

Des opérateurs prédéfinis sont également disponibles. Ils doivent être précédés de "lobby/" lorsqu'ils sont spécifiés.

| Opérateurs | Signification | Exemple |
| - | - | - |
| memberCount | nombre de joueurs dans un lobby | lobby/memberCount eq 5 |
| maxMemberCount | nombre maximal de joueurs autorisés dans un lobby | lobby/maxMemberCount gt 10 |
| memberCountRemaining | nombre restant de joueurs pouvant rejoindre le lobby | lobby/memberCountRemaining gt 0 |
| membershipLock | état de verrouillage des lobbies, doit être égal à 'Unlocked' ou 'Locked' | lobby/membershipLock eq 'Unlocked' |
| amOwner | lobbies dont vous êtes propriétaire, doit être égal à 'true' | lobby/amOwner eq 'true' |
| amMember | lobbies dont vous êtes membre, doit être égal à 'true' | lobby/amMember eq 'true' |
| amServer | lobbies appartenant à des clients que le serveur a rejoints, doit être égal à 'true' | lobby/amServer eq 'true' |

## Tri des résultats de recherche

Chaîne de style OData qui contient le tri de cette requête dans l'ordre croissant ("asc") ou décroissant ("desc"). Les clauses OrderBy peuvent être utilisées pour toutes les clés de recherche numériques ou les clés de recherche prédéfinies numériques. Pour trier selon la proximité avec un nombre, le moniker distance peut être utilisé afin de trier selon la distance par rapport à la clé de recherche numérique donnée. Vous ne pouvez pas utiliser l'ordre croissant ou décroissant avec le tri par distance. Ce champ ne prend en charge qu'une seule clause de tri ou une seule clause de distance. Si aucun tri n'est fourni ou si un départage est nécessaire pour le tri donné, le tri par défaut est décroissant selon l'heure de création.

| Exemple | Signification |
| - | - |
| number\_key1 asc | tri croissant selon la clé de recherche numérique |
| lobby/memberCount desc | tri décroissant selon la clé de recherche numérique |
| distance(number\_key1 = 5) | tri selon la distance par rapport au nombre donné |
| | tri décroissant selon l'heure de création |

### Tri et filtrage des résultats de recherche - Exemple de code

```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​
```

## Rejoindre un lobby

Le tableau suivant répertorie les fonctions comparables utilisées par MPSD et PlayFab Multiplayer pour rejoindre des sessions ou des lobbies.

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

<Note>Rejoindre un lobby nécessite une chaîne de connexion. En général, l'hôte du lobby définit cette chaîne de connexion dans son activité ou l'envoie via une invitation. Pour obtenir la chaîne de connexion, vous devez appeler `PFLobbyGetConnectionString`.</Note>

### Rejoindre un lobby - Exemple de code

Définissez la configuration de jonction initiale, puis rejoignez le lobby.

```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))
{
    //...
} 
```

## Mettre à jour un lobby

Le tableau suivant répertorie les fonctions comparables utilisées par MPSD et PlayFab Multiplayer pour mettre à jour une session ou un lobby.

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

<Note>`PFLobbyPostUpdate` peut être utilisé pour mettre à jour à la fois les propriétés du lobby et les propriétés des membres. Vous pouvez mettre à jour l'un de ces types de propriétés, ou les deux, en un seul appel à la fonction.</Note>

### Mettre à jour un lobby - Exemple de code (propriétés du lobby)

```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))
{
    //...
} 
```

### Mettre à jour un lobby - Exemple de code (propriétés des membres)

```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))
{
    //...
}
```

## Matchmaking

Les API de matchmaking de PlayFab Multiplayer sont relativement similaires à celles de MPSD.

| MPSD | PlayFab Multiplayer |
| - | - |
| Configuration via des hoppers SmartMatch | Repose sur des files d'attente de matchmaking |
| Le hopper est lié à un modèle de session MPSD | Les règles de matchmaking s'appliquent à la file d'attente |
| Les règles de matchmaking s'appliquent au hopper | Le matchmaking démarre via un ticket de match |
| Le matchmaking nécessite une session MPSD existante | Le résultat du matchmaking est un nouveau lobby PlayFab |
| Le résultat du matchmaking est une nouvelle session MPSD | Prend en charge l'allocation de serveurs PlayFab Multiplayer |

<Note>Les files d'attente de matchmaking doivent être configurées via PlayFab Game Manager.</Note>

## Modifications de l'état du matchmaking

Le tableau suivant répertorie les fonctions comparables utilisées par MPSD et PlayFab Multiplayer pour gérer les événements liés au matchmaking.

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

### Modifications de l'état du matchmaking - Exemple de code

Indiquez à la bibliothèque que vous commencez à traiter les modifications d'état. Traitez chaque modification d'état en file d'attente, puis indiquez que vous avez terminé de traiter les modifications d'état.

```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))
{
    //...
}
```

## Démarrer le matchmaking

| MPSD | PlayFab Multiplayer |
| - | - |
| Appels de création de session MPSD... | `PFMultiplayerCreateMatchmakingTicket` |
| `XblMatchmakingCreateMatchTicketAsync` | `PFMultiplayerJoinMatchmakingTicketFromId` |
| `XblMatchmakingCreateMatchTicketResult` | `PFMatchmakingTicketGetStatus` |
| `XblMultiplayerSessionMatchmakingServer` | `PFMatchmakingTicketGetMatch` |
| Appels de jonction de session MPSD... | `PFMultiplayerJoinArrangedLobby` |

### Démarrer le matchmaking - Exemple de code

```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>Le matchmaking ne démarre pas tant que tous les membres spécifiés dans le champ `membersToMatchWith` n'ont pas rejoint.</Note>

Ensuite, une fois qu'un match a été trouvé et que la modification d'état est renvoyée, rejoignez le lobby organisé.

```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))
                {
                    //...
                }
            }
        }
    }
}
```

## Nettoyage

Le tableau suivant répertorie les fonctions comparables utilisées par MPSD et PlayFab Multiplayer pour le nettoyage et l'arrêt.

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

<Note>Veillez à quitter tous les lobbies actifs et à détruire tous les tickets de matchmaking en cours avant d'appeler `PFMultiplayerUninitialize`.</Note>

### Nettoyage - Exemple de code

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

## Activités

Le tableau suivant répertorie les fonctions comparables utilisées par MPSD et MPA pour gérer les activités.

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

<Note>Lorsque vous définissez une activité ou envoyez une invitation, veillez à utiliser la chaîne de connexion renvoyée par `PFLobbyGetConnectionString`.</Note>

### Activités - Exemple de code

```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
{
    //...
}
```

## Invitations

Le tableau suivant répertorie les fonctions comparables utilisées par MPSD et MPA pour envoyer et recevoir des invitations.

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

### Invitations - Exemple de code (interface utilisateur du titre)

```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
{
    //...
}
```

### Invitations - Exemple de code (interface utilisateur XBOX)

```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` utilise l'activité actuellement définie. Vous devez définir une activité à l'aide de `XblMultiplayerActivitySetActivityAsync` avant d'utiliser cette fonction.</Note>

## Joueurs récents

Le tableau suivant montre comment la liste des joueurs récents est gérée avec MPSD et MPA.

| MPSD | MPA |
| - | - |
| Les joueurs doivent se trouver dans la même session MPSD | `XblMultiplayerActivityUpdateRecentPlayers` |
| La propriété `gameplay` de la session est définie sur `true` | `XblMultiplayerActivityFlushRecentPlayersAsync` |
| Les deux joueurs sont marqués comme actifs | |

<Note>Pour éviter la limitation, il est recommandé de regrouper les appels à `XblMultiplayerActivityUpdateRecentPlayers`.</Note>

### Joueurs récents - Exemple de code

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

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


## Related topics

- [Débogage local des serveurs de jeu et intégration à PlayFab](/fr/services/playfab/multiplayer/servers/locally-debugging-game-servers-and-integration-with-playfab.md)
- [Utilisation de PlayFab Party avec MPSD](/fr/services/playfab/multiplayer/networking/using-mpsd.md)
- [Concepts](/fr/services/xbox-services/multiplayer/mpsd/concepts/index.md)
- [MPA](/fr/services/xbox-services/multiplayer/mpa/index.md)
- [Conseils de conception multijoueur pour XBOX et PC](/fr/services/xbox-services/multiplayer/overviews/multiplayer-design-guidance-xbox-pc-gdk.md)
