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

# 非同步 Lobby 和 Matchmaking C++ SDK 作業指南

> 了解 PlayFab Lobby 和 Matchmaking C++ SDK 中的非同步作業、輪詢和狀態變更通知，以及多人遊戲的最佳做法。

# 非同步作業和通知

對於可能較慢或計算成本較高的作業，PlayFab Lobby 和 Matchmaking SDK 會公開非同步 API。非同步 API 讓您能夠從主執行緒啟動成本高或較慢的作業，並在您選擇的執行緒上輪詢這些作業是否完成。相同的輪詢機制也用於將 SDK 更新的非同步通知傳遞給您的遊戲程式碼。本頁面概述 PlayFab Lobby 和 Matchmaking SDK 的非同步 API 模式，以及針對這些模式進行程式設計的最佳做法。

## 基本 API 模式

在 PlayFab Lobby 和 Matchmaking SDK 中，需要注意兩種類型的非同步 API 模式：

1. [非同步作業](#asynchronous-operations)
2. [非同步通知](#asynchronous-notifications)

<a id="asynchronous-operations" />

### 非同步作業

使用 SDK 的非同步 API 很簡單。啟動和完成非同步作業的一般模式如下：

1. 對您選擇的適當非同步 API 進行一般方法呼叫。您可能會使用的常見非同步作業包括：
   * [PFMultiplayerCreateAndJoinLobby](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pflobby/functions/pfmultiplayercreateandjoinlobby)。
   * [PFMultiplayerJoinLobby](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pflobby/functions/pfmultiplayerjoinlobby)。
   * [PFLobbyPostUpdate](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pflobby/functions/pflobbypostupdate)。
   * [PFMultiplayerCreateMatchmakingTicket](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pfmatchmaking/functions/pfmultiplayercreatematchmakingticket)。

2. 使用 **SUCCEEDED()** 或 **FAILED()** 巨集檢查 API 的 **HRESULT** 傳回值。這個同步傳回的值會告訴您作業是否已成功啟動。

<Warning>
  非同步 API 呼叫的同步傳回值**不會**告訴您作業是否已成功完成。如需同步與非同步錯誤的詳細資訊，請參閱 SDK 的[錯誤處理文件](/zh-TW/services/playfab/multiplayer/lobby/lobby-and-matchmaking-client-sdk-errors#synchronous-vs-asynchronous-errors)。
</Warning>

3. 尋找由 [PFMultiplayerStartProcessingLobbyStateChanges()](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pflobby/functions/pfmultiplayerstartprocessinglobbystatechanges) 或 [PFMultiplayerStartProcessingMatchmakingStateChanges](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pfmatchmaking/functions/pfmultiplayerstartprocessingmatchmakingstatechanges) 提供的相關作業「完成狀態變更」，以輪詢非同步作業是否完成。**PFMultiplayerCreateAndJoinLobby()** 相關「完成狀態變更」的範例是 [PFLobbyCreateAndJoinLobbyCompletedStateChange](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pflobby/structs/pflobbycreateandjoinlobbycompletedstatechange)。如需「狀態變更」是什麼及其運作方式的更詳細資訊，請參閱[狀態變更](#state-changes)一節。

4. 檢查完成狀態變更的 **result** 值，以判斷作業是成功還是失敗。如需這些錯誤值的更詳細資訊，請參閱 SDK 的[錯誤處理文件](/zh-TW/services/playfab/multiplayer/lobby/lobby-and-matchmaking-client-sdk-errors#synchronous-vs-asynchronous-errors)。

<a id="asynchronous-notifications" />

### 非同步通知

某些功能會產生 Lobby 和 Matchmaking SDK 變更的非同步通知。

常見的通知包括：

1. [大廳更新通知](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pflobby/structs/pflobbyupdatedstatechange)。
2. [大廳中斷連線通知](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pflobby/structs/pflobbydisconnectingstatechange)。
3. [配對票證狀態變更通知](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pfmatchmaking/structs/pfmatchmakingticketstatuschangedstatechange)。

SDK 會透過 [PFMultiplayerStartProcessingLobbyStateChanges()](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pflobby/functions/pfmultiplayerstartprocessinglobbystatechanges) 和 [PFMultiplayerStartProcessingMatchmakingStateChanges](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pfmatchmaking/functions/pfmultiplayerstartprocessingmatchmakingstatechanges)，以「狀態變更」的形式將這些非同步通知提供給您。

如需「狀態變更」是什麼及其運作方式的更詳細資訊，請參閱[狀態變更](#state-changes)一節。

<a id="state-changes" />

## 狀態變更

Lobby 和 Matchmaking SDK 的非同步 API 模型是圍繞 [PFLobbyStateChange](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pflobby/structs/pflobbystatechange) 和 [PFMatchmakingStateChange](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pfmatchmaking/structs/pfmatchmakingstatechange) 結構建置的。**PFLobbyStateChanges** 會通知您大廳子系統的變更，而 **PFMatchmakingStateChanges** 會通知您配對子系統的變更。

這些「狀態變更」是來自 SDK 之事件的非同步通知。這些通知會在內部排入佇列，您可以呼叫 [PFMultiplayerStartProcessingLobbyStateChanges()](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pflobby/functions/pfmultiplayerstartprocessinglobbystatechanges) 和 [PFMultiplayerStartProcessingMatchmakingStateChanges](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pfmatchmaking/functions/pfmultiplayerstartprocessingmatchmakingstatechanges) 來處理它們。這些函式會以清單形式傳回 (各自 API 子系統的) 所有已排入佇列的狀態變更，您可以逐一查看並個別處理。每個狀態變更都有對應的 *stateChangeType* 欄位，可以檢查該欄位以判斷您收到的是哪個特定狀態變更的通知。一旦您知道收到的是哪個狀態變更，就可以將一般的 **PFLobbyStateChange** 或 **PFMatchmakingStateChange** 結構轉換為更具體的狀態變更結構類型，以檢查該事件的特定資料。

通常，狀態變更處理會實作為一個簡單的 switch 陳述式，將每個狀態變更委派給處理常式。

處理完來自 **PFMultiplayerStartProcessingLobbyStateChanges** 或 **PFMultiplayerStartProcessingMatchmakingStateChanges** 的狀態變更清單後，必須分別將其傳回給 [PFMultiplayerFinishProcessingMatchmakingStateChanges()](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pfmatchmaking/functions/pfmultiplayerfinishprocessingmatchmakingstatechanges) 或 [PFMultiplayerFinishProcessingMatchmakingStateChanges()](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pfmatchmaking/functions/pfmultiplayerfinishprocessingmatchmakingstatechanges)。

```cpp theme={null}
//
// Process Lobby state changes
//
uint32_t lobbyStateChangeCount;
const PFLobbyStateChange * const * lobbyStateChanges;
HRESULT hr = PFMultiplayerStartProcessingLobbyStateChanges(m_pfmHandle, &lobbyStateChangeCount, &lobbyStateChanges);
if (FAILED(hr))
{
    return hr;
}

for (uint32_t i = 0; i < lobbyStateChangeCount; ++i)
{
    const PFLobbyStateChange* stateChange = lobbyStateChanges[i];
    switch (stateChange->stateChangeType)
    {
        case PFLobbyStateChangeType::CreateAndJoinLobbyCompleted:
        {
            HandleCreateAndJoinLobbyCompleted(
                static_cast<const PFLobbyCreateAndJoinLobbyCompletedStateChange*>(stateChange));
            break;
        }
        // add other state change handlers here
    }
}

hr = PFMultiplayerFinishProcessingLobbyStateChanges(m_pfmHandle, lobbyStateChangeCount, lobbyStateChanges);
if (FAILED(hr))
{
    return hr;
}

//
// Process Match state changes
//
uint32_t matchStateChangeCount;
const PFMatchmakingStateChange * const * matchStateChanges;
hr = PFMultiplayerStartProcessingMatchmakingStateChanges(m_pfmHandle, &matchStateChangeCount, &matchStateChanges);
if (FAILED(hr))
{
    return hr;
}

for (uint32_t i = 0; i < matchStateChangeCount; ++i)
{
    const PFMatchmakingStateChange* stateChange = matchStateChanges[i];
    switch (stateChange->stateChangeType)
    {
        case PFMatchmakingStateChangeType::TicketStatusChanged:
        {
            HandleMatchmakingTicketStatusChanged(
                static_cast<const PFMatchmakingTicketStatusChangedStateChange*>(stateChange));
            break;
        }
        // add other state change handlers here
    }
}

hr = PFMultiplayerFinishProcessingMatchmakingStateChanges(m_pfmHandle, matchStateChangeCount, matchStateChanges);
if (FAILED(hr))
{
    return hr;
}
```

## 非同步作業內容

每個非同步 API 都包含一個 `void* asyncContext` 參數。此值是一個傳遞參數，一旦 **PFMultiplayerStartProcessingLobbyStateChanges()** 或 **PFMultiplayerStartProcessingMatchmakingStateChanges()** 提供此 API 呼叫相關的完成狀態變更，就會在其上設定此值。

此值為您提供一種機制，將任意的指標大小內容附加至您的非同步 API 呼叫。這些內容可用於許多情境，包括：

1. 將遊戲專屬資料與 SDK 呼叫建立關聯
2. 以共用識別碼將多個非同步作業連結在一起

使用 SDK 時不一定需要這些非同步內容，但它們可以讓某些遊戲邏輯更容易撰寫。

## 作業佇列

使用非同步 API 時，經常需要將多個非同步作業依序執行，作為更大的非同步流程的一部分。

在 Lobby 和 Matchmaking SDK 中，其中一個例子是建立大廳並為該大廳傳送邀請給朋友。依序執行時，此流程看起來會像這樣：

1. 呼叫 **PFMultiplayerCreateAndJoinLobby()** 以建立並加入 PlayFab 大廳。
2. 等候 **PFLobbyCreateAndJoinLobbyCompletedStateChange** 反映大廳已成功建立並加入。
3. 為每位受邀的朋友呼叫 **PFLobbySendInvite()**。
4. 等候 **PFLobbySendInviteCompletedStateChange** 反映邀請已成功傳送。

對於更複雜的流程和遊戲邏輯，這種依序執行的模式可能較為適當。不過，對於較簡單的流程，SDK 提供了一個旨在簡化遊戲程式碼的替代方案：

SDK 中的許多非同步 API 都支援在先前的作業完全完成之前將相依作業排入佇列。以先前的範例來說，您可以在看到大廳成功建立之前就傳送該大廳的邀請。

實際上，佇列可讓您將一組非同步作業組合在一起、一次全部啟動，並將錯誤處理合併到單一失敗點。

```cpp theme={null}
PFLobbyHandle newLobby;
HRESULT hr = PFMultiplayerCreateAndJoinLobby(m_pfmHandle, myPlayerEntityId, newLobbyConfiguration, nullptr, nullptr, &newLobby);
if (SUCCEEDED(hr))
{
    for (size_t i = 0; SUCCEEDED(hr) && i < friends.size(); ++i)
    {
        hr = PFLobbySendInvite(m_pfmHandle, myPlayerEntityId, friends[i], nullptr);
    }

    if (SUCCEEDED(hr))
    {
        m_lobby = newLobby;
        Log("Created lobby and invited %zu friends!", friends.size());
    }
    else
    {
        // For the purposes of demonstration, we could have a policy that we shouldn't bother with any lobbies where
        // we couldn't invite all of our friends.
        (void) PFLobbyLeave(newLobby, myPlayerEntityId, nullptr);
    }
}
```

## 控制非同步工作

遊戲有時需要控制非同步工作的執行位置，以避免程式庫與遊戲核心 CPU 工作負載之間的 CPU 競爭。

Lobby 和 Matchmaking SDK 可讓您透過[控制執行緒親和性](#controlling-thread-affinity)來控制非同步工作的執行方式

<a id="controlling-thread-affinity" />

### 控制執行緒親和性

根據預設，非同步 SDK 工作是在受到嚴格控制的背景執行緒上完成的。某些遊戲需要對這些背景執行緒的排程*位置*進行粗略的控制，以避免 CPU 競爭。

對於這些遊戲，Lobby 和 Matchmaking SDK 提供了 [PFMultiplayerSetThreadAffinityMask()](/zh-TW/services/playfab/multiplayer/lobby/playfabmultiplayerreference-cpp/pfmultiplayer/functions/pfmultiplayersetthreadaffinitymask)。在支援的平台上，這可讓您限制 SDK 背景執行緒將使用哪些 CPU 核心。如此一來，您就可以保證保留某些核心給您自己的 CPU 工作負載，而不會發生任何競爭。


## Related topics

- [處理 Lobby 和 Matchmaking C++ SDK 錯誤](/zh-TW/services/playfab/multiplayer/lobby/lobby-and-matchmaking-client-sdk-errors.md)
- [Lobby SDK 快速入門](/zh-TW/services/playfab/multiplayer/lobby/lobby-getting-started.md)
- [快速入門 (Windows) - Party 和 Multiplayer](/zh-TW/services/playfab/sdks/unified-sdk/quickstart-windows-party.md)
- [PlayFab Lobby 和 Matchmaking SDK](/zh-TW/services/playfab/multiplayer/lobby/lobby-matchmaking-sdks/lobby-matchmaking-sdks.md)
- [PlayFab Unified SDK 中的記憶體管理](/zh-TW/services/playfab/sdks/unified-sdk/memory-management.md)
