로비 찾기
타이틀에서 플레이어가 다른 게임 내 품질 중에서 맵 및 난이도와 같은 특정 기준 세트를 충족하는 로비를 찾도록 하는 것이 종종 유용합니다. 이 검색 기능을 통해 플레이어는 원하는 사람들과 원하는 게임 세션을 찾을 수 있습니다.
이 도움말에서는 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 | 같음 | string_key1 eq 'CaptureTheFlag' |
lt | 미만 | number_key2 lt 10 |
le | 보다 작거나 같음 | number_key2 le 10 |
gt | 보다 큼 | number_key3 gt 100 |
ge | 보다 크거나 같음 | number_key3 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 절은 숫자인 검색 번호 키 또는 미리 정의된 검색 키에 사용할 수 있습니다. 숫자와 가장 가까운 거리를 기준으로 정렬하려면 모니커 거리를 사용하여 지정된 숫자 검색 키로부터의 거리를 기준으로 정렬할 수 있습니다. 거리 정렬에는 오름차순 또는 내림차순을 사용할 수 없습니다. 이 필드는 정렬 절 하나 또는 거리 절 하나만 지원합니다. 정렬이 제공되지 않거나 지정된 정렬에 연결선이 필요한 경우 기본 정렬은 생성 시간에 따라 내림차순입니다.
예제 | 의미 |
---|---|
number_key1 asc | 숫자 검색 키 오름차순으로 정렬 |
lobby/memberCount desc | 숫자 검색 키 내림차순으로 정렬 |
distance(number_key1 = 5) | 지정된 숫자와 거리를 기준으로 정렬 |
기본값 | 생성 시간 내림차순으로 정렬 |
로비 및 매치 메이킹 SDK를 사용하여 로비를 찾는 예제
이 예제에서 플레이어는 다음 요구 사항을 가진 모든 변수를 찾으려고 합니다.
- 게임 모드는 "DeathMatch"입니다.
- 경쟁 스타일은 "Ranked"입니다.
- 플레이어의 기술 수준이 로비의 최소 및 최대 기술 제한 내에 있습니다.
또한 플레이어는 다음 지침에 따라 결과를 정렬하기를 원합니다.
- 플레이어의 기술 수준에 가장 가까운 최적 기술 수준을 가진 스킬은 더 높은 정렬을 해야 합니다.
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
}
}