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

# Migrando do MPSD para o PlayFab Multiplayer e o MPA

> Guia de migração de títulos XBOX do MPSD para os lobbies do PlayFab Multiplayer e o Multiplayer Activity (MPA) para convites, matchmaking e jogadores recentes.

## Introdução

Este documento se destina a desenvolvedores de jogos que usam atualmente o MPSD e desejam passar a usar o PlayFab Multiplayer e o MPA em seus jogos multijogador. O documento aborda os cenários multijogador mais comuns e fornece trechos de código que mostram como usar o PlayFab Multiplayer com o MPA.

### Visão geral do Multiplayer Session Directory (MPSD)

* Serviço de sessão completo para compartilhar as informações necessárias para conectar um grupo de usuários
* Integrado à interface do usuário do XBOX para a funcionalidade de convites e entrada
* Totalmente integrado ao matchmaking do SmartMatch
* As sessões são derivadas de modelos de sessão predefinidos
* Funcionalidade integrada de detecção de conectividade e fluxo de sessão
* Disponível como serviço a serviço

### Visão geral do Multiplayer Activity Service (MPA)

* Serviço leve para simplificar a integração com o XBOX Live para atividades de jogadores, convites e jogadores recentes
* Coordena-se com o shell e o sistema operacional do console para enviar/aceitar convites e receber entradas
* Sem gerenciamento de sessão nem matchmaking
* Disponível como serviço a serviço

### Visão geral do PlayFab Multiplayer

* Serviço completo de lobby multijogador que inclui funcionalidade de pesquisa e navegação de lobbies
* Notificações de serviço multiplataforma em tempo real com integração de API transparente
* Serviço completo de matchmaking com suporte a notificações em tempo real

## Inicialização

A tabela a seguir mostra uma lista de funções equivalentes usadas pelo MPSD e pelo PlayFab Multiplayer para a inicialização.

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

### Inicialização - Código de exemplo

Inicialize a biblioteca com o titleID do PlayFab e defina o token de entidade recebido durante o login no serviço PlayFab.

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

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

## Alterações de estado do lobby

A tabela a seguir mostra uma lista de funções equivalentes usadas pelo MPSD e pelo PlayFab Multiplayer para tratar eventos relacionados a sessões/lobbies.

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

### Alterações de estado do lobby - Código de exemplo

Notifique a biblioteca de que você está começando a processar as alterações de estado. Trate cada alteração de estado na fila e, em seguida, notifique que terminou de processar as alterações de estado.

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

## Criar lobby

A tabela a seguir mostra uma lista de funções equivalentes usadas pelo MPSD e pelo PlayFab Multiplayer para criar uma sessão/lobby e entrar nela.

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

<Note>Nenhuma instalação ou configuração adicional no PlayFab Game Manager é necessária para criar um lobby. Toda a configuração pode ser feita no código.</Note>

### Criar lobby - Código de exemplo

Configure o lobby e defina as propriedades iniciais do lobby ou dos membros e, em seguida, crie o lobby e entre nele.

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

## Encontrar lobbies

A tabela a seguir mostra uma lista de funções equivalentes usadas pelo MPSD e pelo PlayFab Multiplayer para pesquisar sessões/lobbies.

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

### Encontrar lobbies - Código de exemplo

Defina a configuração de pesquisa e, em seguida, pesquise 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))
{
    //...
} 
```

Em seguida, quando a alteração de estado do evento for retornada, processe os resultados da pesquisa.

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

## Chaves de pesquisa de lobby

Somente um conjunto restrito de chaves pode ser usado ao definir propriedades de pesquisa personalizadas.

* Para propriedades de cadeia de caracteres, as seguintes chaves têm suporte: string\_key1, string\_key2, \[...] string\_key30
* Para propriedades numéricas, as seguintes chaves têm suporte: number\_key1, number\_key2, \[...] number\_key30

## Operadores de pesquisa de lobby

As cadeias de consulta das APIs **FindLobbies** são estruturadas em uma sintaxe semelhante à do OData. O tamanho máximo da cadeia de filtro é de 600 caracteres.

Estes operadores OData podem ser usados para compor cadeias de consulta. Os operadores diferenciam maiúsculas de minúsculas.

| Operadores | Significado | Exemplo |
| - | - | - |
| eq | igual a | string\_key1 eq 'CaptureTheFlag' |
| lt | menor que | number\_key2 lt 10 |
| le | menor ou igual a | number\_key2 le 10 |
| gt | maior que | number\_key3 gt 100 |
| ge | maior ou igual a | number\_key3 ge 100 |
| ne | diferente de | string\_key1 ne 'CaptureTheFlag' |
| and | e | string\_key1 eq 'CaptureTheFlag' and number\_key2 lt 10 |

<Note>Ao comparar propriedades de cadeia de caracteres, certifique-se de colocar o valor comparado entre aspas simples. Por exemplo, "string\_key1 eq **'SOME STRING VALUE'**". As propriedades numéricas não precisam ficar entre aspas.</Note>

Também há operadores predefinidos disponíveis para uso. Eles devem ter o prefixo "lobby/" ao serem especificados.

| Operadores | Significado | Exemplo |
| - | - | - |
| memberCount | número de jogadores em um lobby | lobby/memberCount eq 5 |
| maxMemberCount | número máximo de jogadores permitidos em um lobby | lobby/maxMemberCount gt 10 |
| memberCountRemaining | número restante de jogadores que podem entrar no lobby | lobby/memberCountRemaining gt 0 |
| membershipLock | status de bloqueio dos lobbies; deve ser igual a 'Unlocked' ou 'Locked' | lobby/membershipLock eq 'Unlocked' |
| amOwner | lobbies dos quais você é o proprietário; deve ser igual a 'true' | lobby/amOwner eq 'true' |
| amMember | lobbies dos quais você é membro; deve ser igual a 'true' | lobby/amMember eq 'true' |
| amServer | lobbies pertencentes a clientes nos quais o servidor entrou; deve ser igual a 'true' | lobby/amServer eq 'true' |

## Classificando os resultados da pesquisa

Cadeia no estilo OData que contém a classificação desta consulta em ordem crescente ("asc") ou decrescente ("desc"). As cláusulas OrderBy podem ser usadas para qualquer uma das chaves numéricas de pesquisa ou das chaves de pesquisa predefinidas que sejam numéricas. Para classificar pela proximidade de um número, o moniker distance pode ser usado para classificar pela distância em relação à chave numérica de pesquisa informada. Não é possível usar ordem crescente ou decrescente com a classificação por distância. Este campo só oferece suporte a uma cláusula de classificação ou a uma cláusula de distância. Se nenhuma classificação for fornecida ou se for necessário um desempate para a classificação informada, a classificação padrão será decrescente com base no horário de criação.

| Exemplo | Significado |
| - | - |
| number\_key1 asc | ordenar pela chave numérica de pesquisa em ordem crescente |
| lobby/memberCount desc | ordenar pela chave numérica de pesquisa em ordem decrescente |
| distance(number\_key1 = 5) | classificar pela distância em relação ao número informado |
| | ordenar pelo horário de criação em ordem decrescente |

### Classificando e filtrando os resultados da pesquisa - Código de exemplo

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

## Entrar no lobby

A tabela a seguir mostra uma lista de funções equivalentes usadas pelo MPSD e pelo PlayFab Multiplayer para entrar em sessões/lobbies.

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

<Note>Entrar em um lobby requer uma cadeia de conexão. Normalmente, o host do lobby define essa cadeia de conexão em sua atividade ou a envia por meio de um convite. Para obter a cadeia de conexão, você precisa chamar `PFLobbyGetConnectionString`.</Note>

### Entrar no lobby - Código de exemplo

Defina a configuração inicial de entrada e, em seguida, entre no 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))
{
    //...
} 
```

## Atualizar o lobby

A tabela a seguir mostra uma lista de funções equivalentes usadas pelo MPSD e pelo PlayFab Multiplayer para atualizar uma sessão/lobby.

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

<Note>`PFLobbyPostUpdate` pode ser usado para atualizar tanto as propriedades do lobby quanto as propriedades dos membros. Você pode atualizar um ou ambos os tipos de propriedades com uma única chamada à função.</Note>

### Atualizar o lobby - Código de exemplo (propriedades do 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))
{
    //...
} 
```

### Atualizar o lobby - Código de exemplo (propriedades dos membros)

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

As APIs de matchmaking do PlayFab Multiplayer são relativamente semelhantes às APIs de matchmaking do MPSD.

| MPSD | PlayFab Multiplayer |
| - | - |
| Configuração por meio de hoppers do Smartmatch | Baseado em filas de matchmaking |
| O hopper é vinculado a um modelo de sessão do MPSD | As regras de matchmaking se aplicam à fila |
| As regras de matchmaking se aplicam ao hopper | O matchmaking começa por meio de um tíquete de partida |
| O matchmaking exige uma sessão do MPSD existente | O resultado do matchmaking é um novo lobby do PlayFab |
| O resultado do matchmaking é uma nova sessão do MPSD | Oferece suporte à alocação de servidores do PlayFab Multiplayer |

<Note>As filas de matchmaking devem ser configuradas por meio do PlayFab Game Manager.</Note>

## Alterações de estado do matchmaking

A tabela a seguir mostra uma lista de funções equivalentes usadas pelo MPSD e pelo PlayFab Multiplayer para tratar eventos relacionados ao matchmaking.

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

### Alterações de estado do matchmaking - Código de exemplo

Notifique a biblioteca de que você está começando a processar as alterações de estado. Trate cada alteração de estado na fila e, em seguida, notifique que terminou de processar as alterações de estado.

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

## Iniciar o matchmaking

| MPSD | PlayFab Multiplayer |
| - | - |
| Chamadas para criar a sessão do MPSD... | `PFMultiplayerCreateMatchmakingTicket` |
| `XblMatchmakingCreateMatchTicketAsync` | `PFMultiplayerJoinMatchmakingTicketFromId` |
| `XblMatchmakingCreateMatchTicketResult` | `PFMatchmakingTicketGetStatus` |
| `XblMultiplayerSessionMatchmakingServer` | `PFMatchmakingTicketGetMatch` |
| Chamadas para entrar na sessão do MPSD... | `PFMultiplayerJoinArrangedLobby` |

### Iniciar o matchmaking - Código de exemplo

```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>O matchmaking não começará até que todos os especificados no campo `membersToMatchWith` tenham entrado.</Note>

Em seguida, quando uma partida for encontrada e a alteração de estado for retornada, entre no lobby combinado.

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

## Limpeza

A tabela a seguir mostra uma lista de funções equivalentes usadas pelo MPSD e pelo PlayFab Multiplayer para limpeza e encerramento.

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

<Note>Certifique-se de sair de todos os lobbies ativos e destruir todos os tíquetes de matchmaking em andamento antes de chamar `PFMultiplayerUninitialize`.</Note>

### Limpeza - Código de exemplo

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

## Atividades

A tabela a seguir mostra uma lista de funções equivalentes usadas pelo MPSD e pelo MPA para gerenciar atividades.

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

<Note>Ao definir uma atividade ou enviar um convite, certifique-se de usar a cadeia de conexão retornada por `PFLobbyGetConnectionString`.</Note>

### Atividades - Código de exemplo

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

## Convites

A tabela a seguir mostra uma lista de funções equivalentes usadas pelo MPSD e pelo MPA para enviar e receber convites.

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

### Convites - Código de exemplo (interface do usuário do título)

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

### Convites - Código de exemplo (interface do usuário do 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` usa a atividade definida no momento. Você deve definir uma atividade usando `XblMultiplayerActivitySetActivityAsync` antes de usar essa função.</Note>

## Jogadores recentes

A tabela a seguir mostra como a lista de jogadores recentes é gerenciada ao usar o MPSD e o MPA.

| MPSD | MPA |
| - | - |
| Os jogadores devem estar na mesma sessão do MPSD | `XblMultiplayerActivityUpdateRecentPlayers` |
| A sessão tem a propriedade `gameplay` definida como `true` | `XblMultiplayerActivityFlushRecentPlayersAsync` |
| Ambos os jogadores estão marcados como ativos | |

<Note>Para evitar a limitação de taxa, a prática recomendada é agrupar as chamadas a `XblMultiplayerActivityUpdateRecentPlayers`.</Note>

### RecentPlayers - Código de exemplo

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

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


## Related topics

- [Integração do PlayFab para títulos dos serviços XBOX](/pt-BR/services/xbox-services/playfab-integration.md)
- [Conceitos](/pt-BR/services/xbox-services/multiplayer/mpsd/concepts/index.md)
- [Migrando um árbitro](/pt-BR/services/xbox-services/multiplayer/concepts/live-migrating-an-arbiter.md)
- [Mpa](/pt-BR/services/xbox-services/multiplayer/mpa/index.md)
- [Orientações de design multijogador para XBOX e PC](/pt-BR/services/xbox-services/multiplayer/overviews/multiplayer-design-guidance-xbox-pc-gdk.md)
