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

# 使用 Multiplayer SDK 將 Party 與 Lobby 整合

> 結合 PlayFab Party SDK 與 PlayFab Multiplayer SDK 的逐步解說，讓大廳中的玩家共用單一語音聊天和資料網路。

PlayFab Lobby 和 PlayFab Party 經常一起使用，在讓玩家進入連網工作階段之前建立及協調玩家群組。本文說明如何搭配使用 C++ Party 程式庫與 C++ Multiplayer 程式庫，將大廳作為分享 Party 網路描述元的便利機制。

## 設定 Party 和 Multiplayer SDK

請參閱 Party 和 Lobby 快速入門以開始使用。

### Party

[Party 快速入門](/zh-TW/services/playfab/multiplayer/networking/quickstart)

### Lobby

[Lobby 快速入門](/zh-TW/services/playfab/multiplayer/lobby/lobby-getting-started)

### 初始化 PlayFab Multiplayer SDK

請參閱 [Lobby 快速入門](/zh-TW/services/playfab/multiplayer/lobby/lobby-getting-started#initialize-the-playfab-multiplayer-sdk)以初始化 PlayFab Multiplayer SDK。

### 使用序列化網路描述元字串建立大廳

建立大廳，並在大廳屬性中以文字形式設定 Party 網路描述元。若要將 Party 網路描述元轉換為字元字串，請使用 [PartyManager::SerializeNetworkDescriptor()](/zh-TW/services/playfab/multiplayer/networking/reference/classes/PartyManager/methods/partymanager_serializenetworkdescriptor)。

下列定義是大廳屬性，以及用於搜尋的索引鍵和值。

```cpp theme={null}
const char* c_propertyKey_LobbyName{ "LobbyName" };
const char* c_propertyKey_PartyDescriptor{ "PartyDescriptor" };

const char* c_searchKey_LobbyGroup{ "string_key1" };    // For Key to identify lobby group
const char* c_searchValue_LobbyGroup{ "PartySample" };  // Use a identifiable string for search lobby group

// The reason for setting this value is to get the lobby name only from the search results, 
// and in practice, change it appropriately for the your game.
const char* c_searchKey_LobbyName{ "string_key2" };
```

1. 呼叫 [PFMultiplayerCreateAndJoinLobby](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pflobby/functions/pfmultiplayercreateandjoinlobby)
2. 定期輪詢 [PFMultiplayerStartProcessingLobbyStateChanges](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pflobby/functions/pfmultiplayerstartprocessinglobbystatechanges) 是否有 [PFLobbyCreateAndJoinLobbyCompletedStateChange](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pflobby/functions/pfmultiplayerstartprocessinglobbystatechanges)，以檢查非同步作業是否完成。

```cpp theme={null}
char descriptor[c_maxSerializedNetworkDescriptorStringLength + 1] = {};
// Serialize our local network descriptor for other peers to use
PartyError err = PartyManager::SerializeNetworkDescriptor(&networkDescriptor, descriptor);
if (PARTY_FAILED(err))
{
    // handle immediate create failure
    DEBUGLOG("SerializeNetworkDescriptor failed! %s\n", GetErrorMessage(err));
    return false;
}

std::vector<const char*> lobbyPropertyKeys;
std::vector<const char*> lobbyPropertyValues;
lobbyPropertyKeys.push_back(c_propertyKey_LobbyName);
lobbyPropertyValues.push_back(lobbyName);
lobbyPropertyKeys.push_back(c_propertyKey_PartyDescriptor);
lobbyPropertyValues.push_back(descriptor);

std::vector<const char*> searchPropertyKeys;
std::vector<const char*> searchPropertyValues;
searchPropertyKeys.push_back(c_searchKey_LobbyGroup);
searchPropertyValues.push_back(c_searchValue_LobbyGroup);
searchPropertyKeys.push_back(c_searchKey_LobbyName);
searchPropertyValues.push_back(lobbyName);

PFLobbyCreateConfiguration lobbyConfiguration{};
lobbyConfiguration.maxMemberCount = 16;
lobbyConfiguration.ownerMigrationPolicy = PFLobbyOwnerMigrationPolicy::Automatic;
lobbyConfiguration.accessPolicy = PFLobbyAccessPolicy::Public;
lobbyConfiguration.lobbyPropertyCount = static_cast<uint32_t>(lobbyPropertyKeys.size());
lobbyConfiguration.lobbyPropertyKeys = lobbyPropertyKeys.data();
lobbyConfiguration.lobbyPropertyValues = lobbyPropertyValues.data();
lobbyConfiguration.searchPropertyCount = static_cast<uint32_t>(searchPropertyKeys.size());
lobbyConfiguration.searchPropertyKeys = searchPropertyKeys.data();
lobbyConfiguration.searchPropertyValues = searchPropertyValues.data();

PFLobbyJoinConfiguration memberConfiguration{};

PFLobbyHandle lobby;
HRESULT hr = PFMultiplayerCreateAndJoinLobby(m_pfmHandle, &userEntity, &lobbyConfiguration, &memberConfiguration, nullptr, &lobby);
if (FAILED(hr))
{
    // handle immediate create failure
    DEBUGLOG("PFMultiplayerCreateAndJoinLobby failed! %s\n", PFMultiplayerGetErrorMessage(hr));
    return false;
}

// NOTE: to simplify this quickstart, we'll synchronously block waiting for the CreateAndJoinLobby operation
// to finish. In a real implementation, this polling would be done asynchronously on a background thread/worker.
bool createAndJoinLobbyFinished = false;
while (!createAndJoinLobbyFinished)
{
    uint32_t lobbyStateChangeCount;
    const PFLobbyStateChange* const* lobbyStateChanges;
    HRESULT hr = PFMultiplayerStartProcessingLobbyStateChanges(m_pfmHandle, &lobbyStateChangeCount, &lobbyStateChanges);
    if (FAILED(hr))
    {
        // handle the failure
        DEBUGLOG("PFMultiplayerStartProcessingLobbyStateChanges failed! %s\n", PFMultiplayerGetErrorMessage(hr));
        return false;
    }

    for (uint32_t i = 0; i < lobbyStateChangeCount; ++i)
    {
        const PFLobbyStateChange* stateChange = lobbyStateChanges[i];
        switch (stateChange->stateChangeType)
        {
        case PFLobbyStateChangeType::CreateAndJoinLobbyCompleted:
        {
            auto createAndJoinStateChange =
                static_cast<const PFLobbyCreateAndJoinLobbyCompletedStateChange*>(stateChange);

            if (SUCCEEDED(createAndJoinStateChange->result))
            {
                // lobby successfully created!
                DEBUGLOG("Lobby 0x%p successfully created!\n", createAndJoinStateChange->lobby);
            }
            createAndJoinLobbyFinished = true;
            break;
        }
        }
    }

    hr = PFMultiplayerFinishProcessingLobbyStateChanges(m_pfmHandle, lobbyStateChangeCount, lobbyStateChanges);
    if (FAILED(hr))
    {
        DEBUGLOG("PFMultiplayerFinishProcessingLobbyStateChanges failed! %s\n", PFMultiplayerGetErrorMessage(hr));
        return false;
    }
}
```

### 尋找大廳

如需如何使用尋找大廳的詳細資料，請參閱下列連結：[尋找大廳](/zh-TW/services/playfab/multiplayer/lobby/find-lobbies)

現在您可以使用 Find Lobbies API，透過 `c_searchValue_LobbyType` 搜尋上面建立的大廳，以取得序列化的網路描述元。

1. 呼叫 [PFMultiplayerFindLobbies](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pflobby/functions/pfmultiplayerfindlobbies)

```cpp theme={null}
std::string filterString;
filterString.append(c_searchKey_LobbyGroup);
filterString.append(" eq '");
filterString.append(c_searchValue_LobbyGroup);
filterString.append("'");

PFLobbySearchConfiguration searchConfiguration = { 0 };
searchConfiguration.filterString = filterString.c_str();

HRESULT hr = PFMultiplayerFindLobbies(m_pfmHandle, &localUser, &searchConfiguration, nullptr);
if (FAILED(hr))
{
    // handle immediate find lobbies failure
    printf("PFMultiplayerFindLobbies failed! %s\n", PFMultiplayerGetErrorMessage(hr));
    return false;
}

// NOTE: to simplify this quickstart, we'll synchronously block waiting for the FindLobbies operation
// to finish. In a real implementation, this polling would be done asynchronously on a background thread/worker.
bool findLobbiesFinished = false;
while (!findLobbiesFinished)
{
    uint32_t lobbyStateChangeCount;
    const PFLobbyStateChange* const* lobbyStateChanges;
    HRESULT hr = PFMultiplayerStartProcessingLobbyStateChanges(m_pfmHandle, &lobbyStateChangeCount, &lobbyStateChanges);
    if (FAILED(hr))
    {
        // handle the failure
        printf("PFMultiplayerStartProcessingLobbyStateChanges failed! %s\n", PFMultiplayerGetErrorMessage(hr));
        return false;
    }

    for (uint32_t i = 0; i < lobbyStateChangeCount; ++i)
    {
        const PFLobbyStateChange* stateChange = lobbyStateChanges[i];
        switch (stateChange->stateChangeType)
        {
            case PFLobbyStateChangeType::FindLobbiesCompleted:
            {
                auto findLobbiesStateChange =
                    static_cast<const PFLobbyFindLobbiesCompletedStateChange*>(stateChange);

                if (FAILED(findLobbiesStateChange->result))
                {
                    printf("PFLobbyStateChangeType::FindLobbiesCompleted failed! %s\n", PFMultiplayerGetErrorMessage(findLobbiesStateChange->result));
                    break;
                }

                for (uint32_t i = 0; i < findLobbiesStateChange->searchResultCount; ++i)
                {
                    const PFLobbySearchResult& searchResult = findLobbiesStateChange->searchResults[i];

                    // Use searchResult.connectionString for connecting a lobby later.
                    MyGame::GuiPostLobbySearchResultRow(searchResult); // defined elsewhere
                }
                findLobbiesFinished = true;
                break;
            }
        }
    }

    hr = PFMultiplayerFinishProcessingLobbyStateChanges(m_pfmHandle, lobbyStateChangeCount, lobbyStateChanges);
    if (FAILED(hr))
    {
        printf("PFMultiplayerFinishProcessingLobbyStateChanges failed! %s\n", PFMultiplayerGetErrorMessage(hr));
        return false;
    }
```

### 加入大廳

現在，使用 PFLobbySearchResult 中的 connectionString，加入從先前「尋找大廳」作業取得的大廳。

1. 呼叫 [PFMultiplayerJoinLobby](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pflobby/functions/pfmultiplayerjoinlobby)

```cpp theme={null}
// Fill in the member properties of user for referencing in the game.
const char* playerColorPropertyKey = "PlayerColor";
const char* playerColorPropertyValue = MyGame::GetPlayerColorString(localUser);
std::vector<const char*> memberPropertyKeys;
std::vector<const char*> memberPropertyValues;
memberPropertyKeys.push_back(playerColorPropertyKey);
memberPropertyValues.push_back(playerColorPropertyValue);

PFLobbyJoinConfiguration joinConfig;
joinConfig.memberPropertyCount = static_cast<uint32_t>(memberPropertyKeys.size());
joinConfig.memberPropertyKeys = memberPropertyKeys.data();
joinConfig.memberPropertyValues = memberPropertyValues.data();

// Join the lobby using the connection string
HRESULT hr = PFMultiplayerJoinLobby(m_pfmHandle, &localUser, connectionString, &joinConfig, nullptr, &m_lobby);
if (FAILED(hr))
{
    // handle immediate join lobby failure
    DEBUGLOG("PFMultiplayerJoinLobby failed! %s\n", PFMultiplayerGetErrorMessage(hr));
    return false;
}

// NOTE: to simplify this quickstart, we'll synchronously block waiting for the JoinLobby operation
// to finish. In a real implementation, this polling would be done asynchronously on a background thread/worker.
bool joinLobbyFinished = false;
while (!joinLobbyFinished)
{
    uint32_t lobbyStateChangeCount;
    const PFLobbyStateChange* const* lobbyStateChanges;
    HRESULT hr = PFMultiplayerStartProcessingLobbyStateChanges(m_pfmHandle, &lobbyStateChangeCount, &lobbyStateChanges);
    if (FAILED(hr))
    {
        // handle the failure
        DEBUGLOG("PFMultiplayerStartProcessingLobbyStateChanges failed! %s\n", PFMultiplayerGetErrorMessage(hr));
        return false;
    }

    for (uint32_t i = 0; i < lobbyStateChangeCount; ++i)
    {
        const PFLobbyStateChange* stateChange = lobbyStateChanges[i];
        switch (stateChange->stateChangeType)
        {
        case PFLobbyStateChangeType::JoinLobbyCompleted:
        {
            auto joinStateChange =
                static_cast<const PFLobbyJoinLobbyCompletedStateChange*>(stateChange);

            if (SUCCEEDED(joinStateChange->result))
            {
                // lobby successfully joined!
                m_lobby = joinStateChange->lobby;

                uint32_t propertyCount;
                const char* const* keys;
                HRESULT hr = PFLobbyGetLobbyPropertyKeys(joinStateChange->lobby, &propertyCount, &keys);
                if (SUCCEEDED(hr))
                {
                    std::string descriptor;
                    for (uint32_t idx = 0; idx < propertyCount; idx++)
                    {
                        const char* value;
                        hr = PFLobbyGetLobbyProperty(joinStateChange->lobby, keys[idx], &value);
                        if (SUCCEEDED(hr))
                        {
                            if (strcmp(keys[idx], c_propertyKey_PartyDescriptor) == 0 && value)
                            {
                                descriptor = value;
                            }
                        }
                    }
                    if (!descriptor.empty())
                    {
                        partyDescriptor = descriptor;
                    }
                    else
                    {
                        // report asynchronous failure
                        DEBUGLOG("Failed to join lobby 0x%p! No Party descriptor found\n",
                            joinStateChange->lobby);
                    }
                }
            }
            joinLobbyFinished = true;
            break;
        }
        }
    }

    hr = PFMultiplayerFinishProcessingLobbyStateChanges(m_pfmHandle, lobbyStateChangeCount, lobbyStateChanges);
    if (FAILED(hr))
    {
        DEBUGLOG("PFMultiplayerFinishProcessingLobbyStateChanges failed! %s\n", PFMultiplayerGetErrorMessage(hr));
        return false;
    }
}
```

## 後續步驟

若要連線到 Party 網路，請閱讀 [Party 快速入門：連線到 Party 網路](/zh-TW/services/playfab/multiplayer/networking/quickstart#connect-to-a-party-network)以深入了解。

## 另請參閱

### Party SDK

* [Party 功能](/zh-TW/services/playfab/multiplayer/networking/party-features)
* [Party SDK](/zh-TW/services/playfab/multiplayer/networking/party-sdks/overview)
* [多人遊戲服務](/zh-TW/services/playfab/multiplayer/mpintro)
* [Party 物件及其關聯](/zh-TW/services/playfab/multiplayer/networking/concepts-objects)
* [Party API 參考文件](/zh-TW/services/playfab/multiplayer/networking/reference/party_members)

### Multiplayer SDK

* [Multiplayer SDK 參考](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pflobby/pflobby_members)
* [Multiplayer SDKs](/zh-TW/services/playfab/multiplayer/lobby/lobby-matchmaking-sdks/lobby-matchmaking-sdks)
* [建立大廳](/zh-TW/services/playfab/multiplayer/lobby/create-a-lobby)
* [非同步作業和通知](/zh-TW/services/playfab/multiplayer/lobby/lobby-and-matchmaking-client-sdk-async)
* [建立可搜尋的大廳](/zh-TW/services/playfab/multiplayer/lobby/define-search-keywords)
* [大廳屬性](/zh-TW/services/playfab/multiplayer/lobby/lobby-properties)


## Related topics

- [與 PlayFab Lobby 和 Match 整合](/zh-TW/services/xbox-services/multiplayer/mpa/concepts/live-mpa-playfab-integration.md)
- [使用 RequestPartyService 從您的服務要求 Party](/zh-TW/services/playfab/multiplayer/networking/party-tutorial-requestpartyservice.md)
- [整合 PlayFab Unreal Engine Marketplace 外掛程式](/zh-TW/services/playfab/multiplayer/networking/party-unreal-engine-oss-playfab-plugin-integration.md)
- [將 PlayFab GSDK 整合至 Unity](/zh-TW/services/playfab/multiplayer/servers/mps-unity.md)
- [XBOX 與 PC 多人遊戲設計指引](/zh-TW/services/xbox-services/multiplayer/overviews/multiplayer-design-guidance-xbox-pc-gdk.md)
