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

# 多人遊戲工作階段瀏覽

> 啟用 XBOX 多人遊戲工作階段瀏覽，讓玩家可以使用遊戲定義的中繼資料 (而非配對) 查詢、篩選和加入開放的遊戲工作階段。

使用本主題讓您的遊戲能讓使用者透過多人遊戲工作階段瀏覽，查詢符合其指定準則的開放多人遊戲工作階段清單。

多人遊戲工作階段瀏覽是在 2016 年 11 月推出的。
在工作階段瀏覽案例中，遊戲中的使用者可以擷取可加入之遊戲工作階段的清單。
此清單中的每個工作階段項目都包含一些有關遊戲的額外中繼資料，使用者可以使用這些資料來協助選擇要加入哪個工作階段。
使用者也可以使用中繼資料篩選工作階段清單。
使用者看到吸引他們的遊戲工作階段之後，就可以加入該工作階段。

使用者也可以建立新的遊戲工作階段，並使用工作階段瀏覽功能招募其他使用者，而不依賴配對。
多人遊戲工作階段瀏覽和傳統配對是不同的。使用多人遊戲工作階段瀏覽時，使用者會
選取想要加入的遊戲工作階段。使用配對時，使用者會選取
「尋找遊戲」選項，嘗試自動將使用者放入適當的遊戲工作階段。

雖然多人遊戲工作階段瀏覽是較手動且較慢的程序，不一定能為使用者選取最佳的遊戲體驗，
但使用者擁有更多的控制權，而且瀏覽功能可能被認為主觀上選到了更好的遊戲。
在遊戲中同時包含多人遊戲工作階段瀏覽和配對案例是很常見的。
一般而言，配對用於常玩的遊戲模式，而多人遊戲工作階段瀏覽則用於自訂遊戲。

## 範例案例

John 想要玩戰鬥競技場多人遊戲，但他想要玩所有使用者都隨機選擇英雄的遊戲。
他可以使用多人遊戲工作階段瀏覽，擷取開放遊戲工作階段的清單，並找到描述中包含「隨機英雄」的工作階段。

如果遊戲的 UI 提供此選項，他可以選取「隨機英雄」遊戲模式，並只擷取標記為 "RandomHero" 遊戲的工作階段。
當 John 找到他喜歡的遊戲工作階段時，就可以加入該工作階段。
有足夠的人加入之後，遊戲工作階段的主機就可以開始遊戲。

## 角色

多人遊戲工作階段瀏覽功能中的工作階段可能會指定它正在為特定角色招募使用者。
例如，使用者可能想要建立一個遊戲工作階段，指定其中包含不超過五個突擊職業，
但必須包含至少兩個治療者角色，以及至少一個坦克角色。

當另一位使用者申請加入工作階段時，他們可以預先選取自己的角色。然後，服務會根據所選角色的可用空位數量，
決定他們是否可以加入工作階段。
如果使用者想要為好友保留兩個位置，可以為工作階段指定「好友」角色，
只有與主機為好友的使用者才能填補專用於「好友」角色的兩個位置。

如需角色的詳細資訊，請參閱[多人遊戲角色](/zh-TW/services/xbox-services/multiplayer/concepts/live-multiplayer-roles)。

## 多人遊戲工作階段瀏覽的運作方式

工作階段瀏覽是透過使用搜尋控制代碼來運作的。
搜尋控制代碼是一個資料封包，其中包含對工作階段的參考，以及有關工作階段的其他中繼資料，例如搜尋屬性。

當遊戲建立符合多人遊戲工作階段瀏覽資格的新遊戲工作階段時，會為該工作階段建立搜尋控制代碼。
搜尋控制代碼會儲存在[多人遊戲服務目錄 (MPSD)](/zh-TW/services/xbox-services/multiplayer/mpsd/live-mpsd-overview) 中，該目錄會維護遊戲的搜尋控制代碼。
當遊戲需要擷取工作階段清單時，遊戲可以將搜尋查詢傳送至 MPSD，MPSD 會傳回符合搜尋準則的搜尋控制代碼清單。
接著，遊戲可以使用工作階段清單向使用者顯示可加入的遊戲清單。
當工作階段已滿或因其他原因無法加入時，您的遊戲可以從 MPSD 移除搜尋控制代碼，
讓該工作階段不會出現在多人遊戲工作階段瀏覽查詢中。

<Note>
  搜尋控制代碼用於向使用者顯示工作階段清單。
</Note>

請勿將搜尋控制代碼用於背景配對。對於背景配對，建議使用 SmartMatch。
如需詳細資訊，請參閱[使用多人遊戲管理員透過 SmartMatch 尋找多人遊戲](/zh-TW/services/xbox-services/multiplayer/mpm/how-to/live-play-multiplayer-with-matchmaking)。

## 為多人遊戲工作階段瀏覽設定工作階段

若要對工作階段使用搜尋控制代碼，工作階段必須將 `searchable` 和 `userAuthorizationStyle` 設定為 `true`。
只有 UWP 遊戲才需要 `userAuthorizationStyle` 功能，但建議為所有 XBOX 遊戲 (包括 Microsoft Game Development Kit (GDK) 遊戲) 實作這些功能。這可確保您遊戲未來的可攜性。

<Note>
  將 `userAuthorizationStyle` 設定為 `true` 會將工作階段的 `readRestriction` 和 `joinRestriction` 變更為 `local`，而不是 `none`。這表示遊戲必須使用搜尋或轉移控制代碼來加入遊戲工作階段。
</Note>

您可以在設定 XBOX 服務時，在工作階段範本中設定這些功能。

<Note>
  對於多人遊戲工作階段瀏覽，只應在用於實際遊戲的工作階段上建立搜尋控制代碼。請勿將其用於大廳工作階段。
</Note>

## 遊戲工作階段擁有權

許多遊戲工作階段類型 (例如 SmartMatch 或僅限好友的工作階段) 不需要主機或擁有者。不過，在設定多人遊戲工作階段瀏覽遊戲時，您可能會想要有擁有者。
擁有由擁有者管理的工作階段對主機有一些好處，例如
從工作階段中移除其他成員，或變更其他成員的擁有權狀態。
若要對工作階段使用擁有者，工作階段必須將 `hasOwners` 設定為 `true`。
使用[多人遊戲角色](/zh-TW/services/xbox-services/multiplayer/concepts/live-multiplayer-roles)時，您可以設定為只有擁有者才能將角色指派給使用者。

<Note>
  如果工作階段的擁有者封鎖了某位 XBOX 成員，該成員就無法加入工作階段。
</Note>

如果所有擁有者都離開工作階段，服務會根據為工作階段定義的 `ownershipPolicy.migration` 原則對工作階段採取動作。
如果原則為 "oldest"，則在工作階段中待最久的使用者會被設定為新的擁有者。
如果原則為 "endsession" (如果未提供，則為預設值)，服務會結束工作階段，並從工作階段中移除所有剩餘的使用者。

## 搜尋控制代碼

搜尋控制代碼以 JSON 結構儲存在 MPSD 中。
除了包含對工作階段的參考之外，搜尋控制代碼還包含用於搜尋的其他中繼資料，稱為搜尋屬性。
工作階段在任何時候都只能有一個為其建立的搜尋控制代碼。
若要使用 XBOX 服務 API (XSAPI) 為工作階段建立搜尋控制代碼，請呼叫 [XblMultiplayerCreateSearchHandleAsync](/zh-TW/reference/live/xsapi-c/multiplayer_c/functions/xblmultiplayercreatesearchhandleasync) 方法。

### 搜尋屬性

搜尋屬性由下列元件組成。

* `tags` 是字串描述元，人們可以使用它來分類遊戲工作階段，就像主題標籤一樣。
  * 標籤必須以字母開頭、不能包含空格，且必須少於 100 個字元。
  * 範例標籤："ProRankOnly"、"norocketlaunchers"、"cityMaps"。

* `strings` 是文字變數。
  * 字串名稱必須以字母開頭、不能包含空格，且必須少於 100 個字元。
  * 範例字串中繼資料："Weapons"="knives+pistols+rifles"、"MapName"="UrbanCityAssault"、"description"="Fun casual game, new people welcome."

* `numbers` 是數值變數。XSAPI 會將數值擷取為 float 類型。
  * 數值名稱必須以字母開頭、不能包含空格，且必須少於 100 個字元。
  * 範例數值中繼資料："MinLevel" = 25、"MaxRank" = 10。

<Note>
  服務會保留標籤和字串值的字母大小寫，但查詢標籤時您必須使用 `tolower()` 函式。這表示標籤和字串值目前都會被視為小寫，即使它們包含大寫字元也一樣。
</Note>

在 XSAPI 中，您可以使用 [XblMultiplayerCreateSearchHandleAsync](/zh-TW/reference/live/xsapi-c/multiplayer_c/functions/xblmultiplayercreatesearchhandleasync) 方法設定搜尋屬性，例如標籤和中繼資料。

### 其他詳細資料

擷取搜尋控制代碼時，結果也會包含有關工作階段的有用資料，例如工作階段是否已關閉，以及是否有任何加入限制。
在 XSAPI 中，這些詳細資料以及搜尋屬性，會包含在搜尋查詢之後傳回的 `XblMultiplayerSearchHandle` 結果中。

### 移除搜尋控制代碼

當您想要從多人遊戲工作階段瀏覽中移除工作階段時，
例如當工作階段已滿或已關閉時，可以刪除搜尋控制代碼。
在 XSAPI 中，使用 [XblMultiplayerDeleteSearchHandleAsync](/zh-TW/reference/live/xsapi-c/multiplayer_c/functions/xblmultiplayerdeletesearchhandleasync) 方法移除搜尋控制代碼。

### 建立包含中繼資料的搜尋控制代碼

下列程式碼示範如何使用 XBOX 多人遊戲 API 為工作階段建立搜尋控制代碼。

#### 平面 C

```cpp theme={null}
size_t tagsCount = 1;
XblMultiplayerSessionTag tags[1] = {};
tags[0] = XblMultiplayerSessionTag{ "SessionTag" };

size_t numberAttributesCount = 1;
XblMultiplayerSessionNumberAttribute numberAttributes[1] = {};
numberAttributes[0] = XblMultiplayerSessionNumberAttribute{ "numberattributename", 1.1 };

size_t strAttributesCount = 1;
XblMultiplayerSessionStringAttribute strAttributes[1] = {};
strAttributes[0] = XblMultiplayerSessionStringAttribute{ "stringattributename", "string attribute value" };

auto asyncBlock = std::make_unique<XAsyncBlock>();
asyncBlock->queue = queue;
asyncBlock->context = nullptr;
asyncBlock->callback = [](XAsyncBlock* asyncBlock)
{
    std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*
    XblMultiplayerSearchHandle searchHandle{ nullptr };
    HRESULT hr = XblMultiplayerCreateSearchHandleResult(asyncBlock, &searchHandle);

    if (SUCCEEDED(hr))
    {
        const char* handleId{ nullptr };
        XblMultiplayerSearchHandleGetId(searchHandle, &handleId);
    }
};

HRESULT hr = XblMultiplayerCreateSearchHandleAsync(
    xblContextHandle,
    &xblMultiplayerSessionReference,
    tags,
    tagsCount,
    numberAttributes,
    numberAttributesCount,
    strAttributes,
    strAttributesCount,
    asyncBlock.get()
);

if (SUCCEEDED(hr))
{
    // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.
    // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*
    asyncBlock.release();
}
```

如需程式碼範例中所使用之函式的詳細資訊，請參閱 [multiplayer\_c](/zh-TW/reference/live/xsapi-c/multiplayer_c/multiplayer_c_members)。

## 建立工作階段的搜尋查詢

擷取搜尋控制代碼清單時，您可以使用搜尋查詢將結果限制為符合特定準則的工作階段。

搜尋查詢語法是 [OData](https://docs.oasis-open.org/odata/odata/v4.0/errata02/os/complete/part2-url-conventions/odata-v4.0-errata02-os-part2-url-conventions-complete.html#_Toc406398092) 樣式的語法，僅支援下列運算子。

| 運算子 | 描述 |
| - | - |
| eq | 等於 |
| ne | 不等於 |
| gt | 大於 |
| ge | 大於或等於 |
| lt | 小於 |
| le | 小於或等於 |
| and | 邏輯 AND |
| or | 邏輯 OR (請參閱下方的注意事項) |

<Note>
  您也可以使用 Lambda 運算式和 `tolower` 標準函式。
</Note>

目前不支援其他 OData 函式。

搜尋標籤或字串值時，您必須在搜尋查詢中使用 `tolower` 函式。
服務只支援搜尋小寫字串。
XBOX 服務只會傳回符合搜尋查詢的前 100 個結果。
如果結果過於廣泛，請確保使用者可以縮小其搜尋查詢的範圍。

<Note>
  篩選字串查詢中支援邏輯 `OR` 陳述式。
</Note>

不過，只允許一個 `OR`，且它必須位於查詢的根層級。
您的查詢中不能有多個 `OR` 陳述式，也不能建立
會導致 `OR` 不在查詢結構最上層的查詢。

### 搜尋控制代碼查詢範例

在 RESTful 呼叫中，"Filter" 是您指定 OData Filter 語言字串的位置，該字串會在查詢中針對所有搜尋控制代碼執行。
在多人遊戲 2015 API 中，您可以使用 [XblMultiplayerGetSearchHandlesAsync](/zh-TW/reference/live/xsapi-c/multiplayer_c/functions/xblmultiplayergetsearchhandlesasync) 方法的 `searchFilter` 參數指定搜尋篩選字串。

目前支援下列篩選案例。

| 篩選依據 | 搜尋篩選字串 |
| - | - |
| 單一成員 xuid '1234566' | "session/memberXuids/any(d:d eq '1234566')" |
| 單一擁有者 xuid '1234566' | "session/ownerXuids/any(d:d eq '1234566')" |
| 等於 'classb' 的字串 'forzacarclass' | "tolower(strings/forzacarclass) eq 'classb'" |
| 等於 6 的數值 'forzaskill' | "numbers/forzaskill eq 6" |
| 大於 1.5 的數值 'halokdratio' | "numbers/halokdratio gt 1.5" |
| 標籤 'coolpeopleonly' | "tags/any(d:tolower(d) eq 'coolpeopleonly')" |
| 不包含標籤 'cursingallowed' 的工作階段 | "tags/any(d:tolower(d) ne 'cursingallowed')" |
| 不包含等於 0 之數值 'rank' 的工作階段 | "numbers/rank ne 0" |
| 不包含等於 'classa' 之字串 'forzacarclass' 的工作階段 | "tolower(strings/forzacarclass) ne 'classa'" |
| 標籤 'coolpeopleonly' 以及等於 7.5 的數值 'halokdratio' | "tags/any(d:tolower(d) eq 'coolpeopleonly') eq true and numbers/halokdratio eq 7.5" |
| 大於或等於 1.5 的數值 'halokdratio'、小於 60 的數值 'rank'，以及小於或等於 5 的數值 'customnumbervalue' | "numbers/halokdratio ge 1.5 and numbers/rank lt 60 and numbers/customnumbervalue le 5" |
| 成就識別碼 '123456' | "achievementIds/any(d:d eq '123456')" |
| 語言代碼 'en' | "language eq 'en'" |
| 排定時間，傳回所有小於或等於指定時間的排定時間 | "session/scheduledTime le '2009-06-15T13:45:30.0900000Z'" |
| 張貼時間，傳回所有小於指定時間的張貼時間 | "session/postedTime lt '2009-06-15T13:45:30.0900000Z'" |
| 工作階段註冊狀態 | "session/registrationState eq 'registered'" |
| 工作階段成員數目等於 5 | "session/membersCount eq 5" |
| 工作階段成員目標數目大於 1 | "session/targetMembersCount gt 1" |
| 工作階段成員數目上限小於 3 | "session/maxMembersCount lt 3" |
| 工作階段成員目標數目與工作階段成員數目之間的差異小於或等於 5 | "session/targetMembersCountRemaining le 5" |
| 工作階段成員數目上限與工作階段成員數目之間的差異大於 2 | "session/maxMembersCountRemaining gt 2" |
| 工作階段成員目標數目與工作階段成員數目之間的差異小於或等於 15。<br /> 如果角色未指定目標，則此查詢會根據工作階段成員數目上限與工作階段成員數目之間的差異進行篩選。 | "session/needs le 15" |
| 角色類型 "lfg" 的角色 "confirmed"，其中具有該角色的成員數目等於 5 | "session/roles/lfg/confirmed/count eq 5" |
| 角色類型 "lfg" 的角色 "confirmed"，其中該角色的目標大於 1。<br /> 如果角色未指定目標，則改用角色的上限。 | "session/roles/lfg/confirmed/target gt 1" |
| 角色類型 "lfg" 的角色 "confirmed"，其中角色的目標與具有該角色之成員數目之間的差異小於或等於 15。<br /> 如果角色未指定目標，則此查詢會根據角色的上限與具有該角色之成員數目之間的差異進行篩選。 | "session/roles/lfg/confirmed/needs le 15" |
| 所有指向包含特定關鍵字之工作階段的搜尋控制代碼 | "session/keywords/any(d:tolower(d) eq 'level2')" |
| 所有指向屬於特定 SCID 之工作階段的搜尋控制代碼 | "session/scid eq '151512315'" |
| 所有指向使用特定範本名稱之工作階段的搜尋控制代碼 | "session/templateName eq 'mytemplate1'" |
| 所有具有標籤 'elite'，或具有大於 15 的數值 'guns' 且字串 'clan' 等於 'purple' 的搜尋控制代碼 | "tags/any(a:tolower(a) eq 'elite') or number/guns gt 15 and string/clan eq 'purple'" |

### 重新整理搜尋結果

您的遊戲應避免自動重新整理工作階段清單。請讓使用者可以選擇使用 UI 手動重新整理清單。
如果使用者縮小其搜尋準則以更妥善地篩選結果，這會很有幫助。
如果使用者嘗試加入工作階段，但該工作階段已滿或已關閉，您的遊戲也應重新整理搜尋結果。

<Note>
  過多的搜尋重新整理可能會導致服務節流。
</Note>

您的遊戲應限制可重新整理查詢的速率。

為了減少服務呼叫量，搜尋控制代碼包含自訂工作階段屬性，可用來儲存和查詢
快速變化的工作階段屬性。這些屬性不應儲存在搜尋屬性中。

### 查詢搜尋控制代碼

下列程式碼示範如何查詢搜尋控制代碼。
API 會傳回 `XblMultiplayerSearchHandle` 物件的集合，代表所有符合查詢的搜尋控制代碼。

#### 平面 C

```cpp theme={null}
auto asyncBlock = std::make_unique<XAsyncBlock>();
asyncBlock->queue = queue;
asyncBlock->context = nullptr;
asyncBlock->callback = [](XAsyncBlock* asyncBlock)
{
    std::unique_ptr<XAsyncBlock> asyncBlockPtr{ asyncBlock }; // Take over ownership of the XAsyncBlock*
    size_t resultCount{ 0 };
    auto hr = XblMultiplayerGetSearchHandlesResultCount(asyncBlock, &resultCount);
    if (SUCCEEDED(hr) && resultCount > 0)
    {
        auto handles = new XblMultiplayerSearchHandle[resultCount];

        hr = XblMultiplayerGetSearchHandlesResult(asyncBlock, handles, resultCount);

        if (SUCCEEDED(hr))
        {
            // Process handles
            for (auto i = 0u; i < resultCount; ++i)
            {
                const char* handleId{ nullptr };
                XblMultiplayerSearchHandleGetId(handles[i], &handleId);

                XblMultiplayerSearchHandleCloseHandle(handles[i]);
            }
        }
    }

};

const char* sessionName{ "MinGameSession" };
const char* orderByAttribute{ nullptr };
bool orderAscending{ false };
const char* searchFilter{ nullptr };
const char* socialGroup{ nullptr };

HRESULT hr = XblMultiplayerGetSearchHandlesAsync(
    xblContextHandle,
    scid,
    sessionName,
    orderByAttribute,
    orderAscending,
    searchFilter,
    socialGroup,
    asyncBlock.get()
);
if (SUCCEEDED(hr))
{
    // The call succeeded, so release the std::unique_ptr ownership of XAsyncBlock* since the callback will take over ownership.
    // If the call fails, the std::unique_ptr will keep ownership and delete the XAsyncBlock*
    asyncBlock.release();
}
```

如需程式碼範例中所使用之函式的詳細資訊，請參閱 [multiplayer\_c](/zh-TW/reference/live/xsapi-c/multiplayer_c/multiplayer_c_members)。

## 使用搜尋控制代碼加入工作階段

使用者擷取想要加入之工作階段的搜尋控制代碼之後，
請確保他們可以使用 [XblMultiplayerWriteSessionByHandleAsync](/zh-TW/reference/live/xsapi-c/multiplayer_c/functions/xblmultiplayerwritesessionbyhandleasync) 將自己新增至工作階段。

<Note>
  [XblMultiplayerWriteSessionAsync](/zh-TW/reference/live/xsapi-c/multiplayer_c/functions/xblmultiplayerwritesessionasync) 方法不能用來加入多人遊戲工作階段瀏覽工作階段。
</Note>


## Related topics

- [多人遊戲概念](/zh-TW/services/xbox-services/multiplayer/concepts/live-multiplayer-concepts-nav.md)
- [多人遊戲常見問題集與疑難排解](/zh-TW/services/xbox-services/multiplayer/mpsd/concepts/live-multiplayer-2015-faq.md)
- [常見的多人遊戲情境](/zh-TW/services/xbox-services/multiplayer/overviews/live-common-multiplayer-scenarios.md)
- [概念](/zh-TW/services/xbox-services/multiplayer/concepts/index.md)
- [多人遊戲工作階段目錄概觀](/zh-TW/services/xbox-services/multiplayer/mpsd/live-mpsd-overview.md)
