ロビーを検索する
マップや難易度など、ゲーム内の特徴の特定の条件セットを満たすロビーをプレイヤーが見つけられるようにすることが多くのタイトルにとって有益です。 この検索機能を使用すると、プレイヤーは必要なユーザーと必要なゲーム セッションを見つけることができます。
この記事では、FindLobbies を使用してプレイヤーがロビーを検索できるようにする方法について説明します。 ゲーム タイトルで使用できるロビーを見つける方法については、「一般的なシナリオ」 を参照してください。
注意
FindLobbies を使用してバックグラウンド マッチメイキングを実装するのはお勧めできません。 そのシナリオでは、マッチメイキング機能を使用することを強くお勧めします。 それ以外の場合には、フィルタリング、並べ替え、検索データ フィールドでのランダム化された値の使用などのその他の手法を使用して、すべてのプレイヤーが同じロビーに参加しようとする際の競合を処理する必要があります。
ロビー検索プロパティとロビー検索の関係について
プレイヤーは、検索プロパティを定義することで、ロビーを検出可能にします。 プレイヤーは、クエリ文字列を使用して FindLobbies を呼び出し、現在アクティブなロビーの中で、定義されている検索プロパティに基づいて検索結果をフィルター処理および並べ替えることで、これらの検出可能なロビーを見つけます。 これらのクエリに一致するロビーは、呼び出し元のプレイヤーに返されます。
検索プロパティの定義の詳細については、「検索可能なロビーの作成」を参照してください 。
FindLobbies の使用方法
FindLobbies を呼び出すときは、フィルター パラメーターを使用して、ロビーのカスタム検索プロパティに基づいて一部の条件セットに一致する検索結果のみを返すようにクエリを制限できます。
さらに、並べ替えパラメーターを使用して、検索プロパティに基づいてサービスから返される結果を並べ替えることができます。 これは、サービスが返す検索結果の数が限られているため便利です。 並べ替えにより、最も関連性の高い検索結果が表示されます。
一般的なシナリオ
FindLobbies 機能がタイトルで使用される一般的な方法をいくつか次に示します。
- タイトル内の特定のゲーム モードのゲーム セッションのロビーを検索する
- フレンドがホストしているゲーム セッションのロビーを見つける
- すべてのローカル プレイヤーに対して十分なプレイヤーを含むゲーム セッションのロビーを見つける
- 予期しないゲーム クライアントまたはゲーム サーバーのクラッシュ後に接続を回復するために既に参加しているロビーを見つけます。
サポートされている検索キー
カスタム検索プロパティを定義するときに使用できるのは、制限付きキーのセットのみです。
- 文字列プロパティでは、string_key1、string_key2、[...] string_key30のキーがサポートされています。
- 数値プロパティでは、number_key1、number_key2、[...] number_key30のキーがサポートされます。
FindLobbies のクエリ文字列の構築
FindLobbies API のクエリ文字列は、OData に似た構文で構成されます。 フィルター文字列の最大サイズは 600 文字です。
これらの OData 演算子を使用してクエリ文字列を作成できます。 演算子では大文字と小文字が区別されます。
演算子 | 意味 | 例 |
---|---|---|
eq | equal to (次の値に等しい) | string_key1 eq 'CaptureTheFlag' |
lt | less than (次の値より小さい) | number_key2 lt 10 |
le | 次の値以下 | number_key2 le 10 |
gt | greater than (次の値より大きい) | number_key3 gt 100 |
ge | 次の値以上 | number_key3 ge 100 |
ne | ne | string_key1 ne 'CaptureTheFlag' |
and | and | string_key1 eq 'CaptureTheFlag' and number_key2 lt 10 |
注意
文字列プロパティを比較する場合には、比較値を単一引用符で囲んでください。 たとえば、"string_key1 eq 'SOME STRING VALUE'“ という具合です。 数値プロパティをラップする必要はありません。
使用可能な定義済みの演算子もあります。 指定するときは、"lobby/" というプレフィックスを付ける必要があります。
演算子 | 意味 | 例 |
---|---|---|
memberCount | ロビー内にいるプレイヤーの数 | lobby/memberCount eq 5 |
MaxMemberCount | ロビーで許可されているプレイヤーの最大数 | lobby/maxMemberCount gt 10 |
memberCountRemaining | ロビーに参加できる残りのプレイヤーの数 | lobby/memberCountRemaining gt 0 |
membershipLock | ロビーのロック状態。値が "Unlocked" または "Locked" に等しくなっている必要があります | lobby/membershipLock eq 'Unlocked' |
amOwner | 自分が所有者になっているロビー。値が 'true' に等しくなっている必要があります | lobby/amOwner eq 'true' |
amMember | 自分がメンバーになっているロビー。値が 'true' に等しくなっている必要があります | lobby/amMember eq 'true' |
amServer | サーバーがクライアント所有のサーバーに参加しているロビー。値が 'true' に等しくなっている必要があります | lobby/amServer eq 'true' |
これらの定数に関する SDK の定義については、こちらを参照してください。
並べ替え
昇順 ("asc") または降順 ("desc") でのこのクエリの並べ替えを含む OData のスタイル文字列。 OrderBy 句は、任意の検索番号キーまたは数値の定義済みの検索キーに使用できます。 数値に近い順に並べ替えるには、モニカー距離を使用して指定した数値検索キーからの距離で並べ替えることができます。 距離を使用した並べ替えで昇順または降順を使用することはできません。 このフィールドでは、並べ替え句が 1 つ、または距離句が 1 つの場合のみをサポートしています。 並べ替えが指定されていないか、または指定された並べ替えにタイブレークが必要な場合には、既定の並べ替え順は作成時間に基づいて降順になります。
例 | 意味 |
---|---|
number_key1 asc | 数値検索キーを使用して昇順で並べ替える |
lobby/memberCount desc | 数値検索キーを使用して降順で並べ替える |
distance(number_key1 = 5) | 指定した数値からの距離で並べ替える |
既定 | 作成時間を使用して降順で並べ替える |
Lobby と Matchmaking SDK を使用してロビーを検索する例
この例では、プレイヤーは次の要件を持つすべてのロビーを検索できます。
- ゲーム モードは "DeathMatch" です
- コンテストのスタイルは "ランク付け" です
- プレイヤーのスキル レベルは、ロビーの最小および最大スキル制限内にあります。
さらに、プレイヤーは結果を次のガイドラインで並べ替えたいと考えています。
- プレイヤーのスキル レベルに最も近い最適なスキル レベルを持つロビーは、より高く並べ替える必要があります
static PFMultiplayerHandle g_pfmHandle = nullptr;
#define SUPPORT_XBL_CROSSPLAY
#define PFLOBBY_SEARCH_KEY_GAME_MODE "string_key1"
#define PFLOBBY_SEARCH_KEY_COMPETITION_STYLE "string_key2"
#define PFLOBBY_SEARCH_KEY_SKILL "number_key1"
#define GAME_MODE_DEATH_MATCH "DeathMatch"
#define COMPETITION_STYLE_RANKED "Ranked"
// Find lobbies based on player's search criteria.
void FindGamesWithRuntimeQuery(
uint32_t minimumSkill,
uint32_t maximumSkill,
uint32_t optimalSkill)
{
PFLobbySearchFriendsFilter friendsFilter;
friendsFilter.includeSteamFriends = true;
#ifdef SUPPORT_XBL_CROSSPLAY
friendsFilter.includeXboxFriendsToken = MyGame::GetLocalUserXboxToken();
#endif // SUPPORT_XBL_CROSSPLAY
// Limit results based on friend's filter.
PFLobbySearchConfiguration searchConfiguration = { 0 };
searchConfiguration.friendsFilter = &friendsFilter;
// Create filter string based on player's search parameters.
std::string filterString;
filterString += PFLOBBY_SEARCH_KEY_GAME_MODE + std::string(" eq ") + "'" + GAME_MODE_DEATH_MATCH + "'";
filterString += " and ";
filterString += PFLOBBY_SEARCH_KEY_COMPETITION_STYLE + std::string(" eq ") + "'" + COMPETITION_STYLE_RANKED + "'";
filterString += " and ";
filterString += PFLOBBY_SEARCH_KEY_SKILL + std::string(" -ge ") + std::to_string(minimumSkill);
filterString += " and ";
filterString += PFLOBBY_SEARCH_KEY_SKILL + std::string(" -le ") + std::to_string(maximumSkill);
// Create sort string based on player's sort preference.
std::string sortString;
sortString += std::string("distance{") + PFLOBBY_SEARCH_KEY_SKILL + "=" + std::to_string(optimalSkill) + "}";
searchConfiguration.filterString = filterString.c_str();
searchConfiguration.sortString = sortString.c_str();
HRESULT hr = PFMultiplayerFindLobbies(g_pfmHandle, &m_localUser, &searchConfiguration, nullptr);
}
void ProcessStateChanges()
{
while (true)
{
uint32_t stateChangeCount;
const PFLobbyStateChange* const* stateChanges;
RETURN_VOID_IF_FAILED(PFMultiplayerStartProcessingLobbyStateChanges(
g_pfmHandle,
&stateChangeCount,
&stateChanges));
for (uint32_t i = 0; i < stateChangeCount; ++i)
{
const PFLobbyStateChange* stateChange = stateChanges[i];
switch (stateChange->stateChangeType)
{
case PFLobbyStateChangeType::FindLobbiesCompleted:
{
GuiPostCurrentLobbySearchResults(
static_cast<const PFLobbyFindLobbiesCompletedStateChange&>(*stateChange));
break;
}
default:
{
break;
}
}
}
RETURN_VOID_IF_FAILED(PFMultiplayerFinishProcessingLobbyStateChanges(
g_pfmHandle,
stateChangeCount,
stateChanges));
}
}
// Update game UI to display search results when a list of matching lobbies is returned.
void GuiPostCurrentLobbySearchResults(
const PFLobbyFindLobbiesCompletedStateChange& stateChange)
{
if (FAILED(stateChange.result))
{
GuiToastErrorAndExitScreen();
return;
}
for (uint32_t i = 0; i < stateChange.searchResultCount; ++i)
{
const PFLobbySearchResult& searchResult = stateChange.searchResults[i];
GuiPostLobbySearchResultRow(searchResult); // defined elsewhere
}
}