쿼리 구문 #

쿼리는 플레이어가 매치메이커를 사용할 때 가장 관련성이 높은 상대방을 찾고, 사용 가능한 대결을 나열할 때 가장 적합한 멀티플레이어 대결을 찾을 수 있는 강력한 도구입니다. 쿼리 표현식은 상대방 또는 사용 가능한 대결을 찾기 위한 사용자의 기준을 정의합니다. 이 쿼리는 결과를 제공하기 위해 쿼리 사용 후 Matchmaker properties 또는 대결 label을(를) 검사하는 큰 AND 명령으로 생각하십시오.

대결 label 쿼리는 레이블이 JSON 값인 경우에만 가능합니다.

쿼리는 구문 field:value을(를) 사용하는 하나 이상의 쿼리 용어로 구성됩니다. 쿼리에는 다수의 용어가 포함될 수 있으며 각 용어는 공백으로 구분됩니다(예: field:value field1:value1).

모든 값 유형에 동일한 구문을 사용할 수 있습니다. 예:

  • 스트링: region:europe
  • 숫자: level:10
  • 숫자 범위: rank:<=5
  • 날짜 범위: created:>"2021-12-25"

쿼리 용어 작성에 대한 자세한 내용은 아래 연산자 섹션을 참조하고 개별 쿼리 용어에 부여된 가중치를 기반으로 결과를 정렬하는 방법에 대한 자세한 내용은 부스팅을 참조하세요.

일치 #

표준 구문은 전체 값과 일치합니다. 즉, 유사성뿐만 아니라 쿼리 값과 반환된 결과 간에 동일성도 있어야 합니다. 예를 들어 mode:free의 쿼리는 freeforall의 모드와 일치하는 대결을 반환하지 않습니다.

쿼리는 또한 대결 배열 내부의 개별 요소를 검사합니다. 예를 들어, 색인된 값: {"field": [5, 10, 15]}은(는) field:5, field:10 또는 field:15 용어를 포함하는 모든 쿼리에 대한 대결로 반환됩니다.

배열 내에서 여러 잠재적 값을 검색하려면 쿼리에서 정규식을 사용합니다. 예를 들어 사용자 그룹의 매치메이킹을 참조하세요.

연산자 #

쿼리 용어를 생성할 때 사용할 수 있는 세 가지 연산자: SHOULD, MUST 및 MUST NOT.

SHOULD #

Should는 쿼리 용어에 사용되는 기본 연산자입니다. 실제로는 결과에 지정된 값이 _있어야 함_을 의미하지만 엄격한 요구 사항은 아닙니다.

예를 들어, region:europe 쿼리를 사용하여 상대방을 검색하는 경우 결과에 양호한 결과(유럽 지역의 상대방을 의미)가 포함되지만, 가능한 경우 그러나 충분히 양호한 결과를 찾을 수 없는 경우 다른 지역의 상대도 포함됩니다.

MUST #

쿼리 용어의 시작 부분에 +에 의해 표시되는 MUST 연산자는 지정된 값의 문자열 요구 사항을 적용합니다. 위와 동일한 예를 사용하지만 MUST 연산자(+region:europe)를 사용하면 유럽 지역의 상대방만 결과에 반환되고 사용 가능한 사람이 충분하지 않은 경우 결과가 반환되지 않음을 의미합니다.

MUST NOT #

MUST NOT 연산자는 쿼리 용어의 시작 부분에 -에 의해 표시됩니다. 쿼리 용어 _제외_에 대한 문자열 요구 사항을 적용합니다. 즉, 반환된 결과에는 해당 값이 전혀 포함되지 않습니다.

예를 들어, 사용자가 수준이 10 이상인 대결을 보고 싶지 않은 경우 쿼리 용어는 -level:>10과(와) 같을 수 있습니다.

범위 #

쿼리에는 숫자와 날짜 범위를 모두 용어로 포함시킬 수 있습니다.

숫자 범위는 >, >=, <, <= 연산자와 함께 쿼리 용어로 사용할 수 있습니다. 예를 들어 created:>"2022-01-01" 2022년 1월 1일 이후에 생성된 결과를 반환하기 위해 날짜가 따옴표로 묶여 있여 구별되는 날짜 범위에 이러한 동일한 연산자를 사용할 수 있습니다.

날짜 범위 쿼리의 경우 가능하면 UTC 초/밀리초를 사용하는 것이 좋습니다.

정규식 #

쿼리는 표현식을 슬래시(/)로 감싸서 지정하는 방식으로 쿼리 용어의 일부로 정규식을 사용할 수 있습니다. 정규식에 대한 자세한 내용은 regexrregex101 웹 사이트를 참조하세요.

예를 들어, freeforall 또는 capturetheflag의 게임 mode과(와) 일치하는 대결을 찾으려면 다음 쿼리를 사용할 수 있습니다. mode:/(freeforall|capturetheflag)/

부스팅 #

위에서 설명한 연산자를 사용하면 지정된 결과가 반환되는지 여부를 설명하기 위해 여러 용어로 쿼리를 작성할 수 있습니다. 또한 쿼리에서 용어의 상대적 중요도를 “부스팅"하여, 반환된 결과의 순서를 선택적으로 정의할 수 있습니다.

이것은 쿼리 용어 끝에 ^ 및 임의의 부스터 번호를 사용하여 수행됩니다.

예를 들어, mode:freeforall^2 mode:capturetheflag 쿼리를 사용하여 대결을 검색하는 경우 결과에는 모두 무료 및 깃발 뺏기 대결이 전부 포함되지만 모두 무료 결과는 깃발 뺏기 결과보다 위에 나열됩니다(즉, “더 나은” 일치).

+ 연산자를 사용하지 않았기 때문에 이 쿼리는 모두 무료 또는 깃발 뺏기 대결이 아닌 결과를 반환할 수도 있지만 이러한 결과는 가장 낮은 결과가 될 것입니다.

이스케이핑 #

정확한 쿼리 결과를 얻으려면 다음 문자 집합을 이스케이프해야 합니다. +-=&|><!(){}[]^\"~*?:\\/

공백 문자가 포함되어 있음에 주의합니다. 예를 들어, “깃발 뺏기” 대결을 쿼리하려면 mode:Capture The Flag 대신 mode:Capture\ The\ Flag을 사용합니다. 후자의 쿼리는 여전히 유효할 수 있지만 “뺏기” mode과(와) 일치하고 어디에나 “깃발"이 포함된 대결을 검색하므로 잘못된 결과가 생성됩니다.

#

친구의 대결 찾기 #

대결 label에 현재 대결에 있는 모든 플레이어의 사용자 ID가 있는 배열 players이(가) 포함된 경우 다음 쿼리를 사용하여 지정된 친구가 속한 대결을 찾을 수 있습니다:

Server
1
2
3
4
5
6
7
8
local nk = require("nakama")

local query = "label.groups:<friend_user_id>"
local matches = nk.match_list(query)

for _, match in ipairs(matches) do
  nk.logger_info(string.format("Match id %s", match.match_id))
end
Server
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
query := "+label.players:<friend_user_id>"
matches, err := nk.MatchList(ctx, query)

if err != nil {
    logger.WithField("err", err).Error("Match listings error.")
    return
}

for _, match := range matches {
    logger.Info("Match id %s", match.MatchId)
}
Server
1
2
3
4
5
6
7
8
function findFriendMatch(context: nkruntime.Context, logger: nkruntime.Logger, nk: nkruntime.Nakama) {
  const query = "+label.players:<friend_user_id>";
  var matches = nk.matchList(query);

  matches.forEach(function (match) {
    logger.info("Match id '%s'", match.matchId);
  });
}

사용자 그룹의 매치메이킹 #

대결 label에 사용자가 속한 모든 그룹의 ID가 있는 배열 groups이(가) 포함된 경우 다음 쿼리를 사용하여 해당 그룹에서만 대결을 찾을 수 있습니다:

Server
1
2
3
4
5
6
7
8
local nk = require("nakama")

local query = "label.groups:/(<groupID>|<groupID2>|<groupID3)/"
local matches = nk.match_list(query)

for _, match in ipairs(matches) do
  nk.logger_info(string.format("Match id %s", match.match_id))
end
Server
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
query := "label.groups:/(<groupID>|<groupID2>|<groupID3)/"
matches, err := nk.MatchList(ctx, query)

if err != nil {
    logger.WithField("err", err).Error("Match listings error.")
    return
}

for _, match := range matches {
    logger.Info("Match id %s", match.MatchId)
}
Server
1
2
3
4
5
6
7
8
function findGroupsMatch(context: nkruntime.Context, logger: nkruntime.Logger, nk: nkruntime.Nakama) {
  const query = "label.groups:/(<groupID>|<groupID2>|<groupID3)/";
  var matches = nk.matchList(query);

  matches.forEach(function (match) {
    logger.info("Match id '%s'", match.matchId);
  });
}

공개 대결 찾기 #

이 예에서 대결 label에는 대결이 새로운 플레이어를 수락하는지 여부를 나타내는 open 값이 포함됩니다. 이 값은 적절한 기준이 충족되면 대결 핸들러에서 업데이트됩니다(예: 충분한 플레이어가 가입했거나 시작할 준비가 되었다고 표시되는 경우).

Server
1
2
3
4
5
6
7
8
local nk = require("nakama")

local query = "+label.open:true label.game_mode:deathmatch"
local matches = nk.match_list(query)

for _, match in ipairs(matches) do
  nk.logger_info(string.format("Match id %s", match.match_id))
end
Server
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
query := "+label.open:true label.game_mode:deathmatch"
matches, err := nk.MatchList(ctx, query)

if err != nil {
    logger.WithField("err", err).Error("Match listings error.")
    return
}

for _, match := range matches {
    logger.Info("Match id %s", match.MatchId)
}
Server
1
2
3
4
5
6
7
8
function findOpenMatches(context: nkruntime.Context, logger: nkruntime.Logger, nk: nkruntime.Nakama) {
  const query = "+label.open:true label.game_mode:deathmatch";
  var matches = nk.matchList(query);

  matches.forEach(function (match) {
    logger.info("Match id '%s'", match.matchId);
  });
}

플레이어 수준에 따른 매치메이킹 #

이 예에서는 수준이 13에서 17 사이인 2-4명의 상대방을 찾는 Skill 수준 15의 플레이어를 위한 매치메이커 티켓을 만듭니다.

Client
1
2
3
4
5
6
7
8
9
const query = "+properties.skill:>=13 +properties.skill:<=17";
const minCount = 2;
const maxCount = 4;

const numericProperties = {
  skill: 15
};

var ticket = await socket.addMatchmaker(query, minCount, maxCount, numericProperties);
Client
1
2
3
4
5
6
7
var query = "+properties.skill:>=13 +properties.skill:<=17";

var numericProperties = new Dictionary<string, int>() {
    {"skill", 15}
};

var matchmakerTicket = await socket.AddMatchmakerAsync(query, 2, 4, numericProperties);
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
auto successCallback = [](const NMatchmakerTicket& ticket)
{
    std::cout << "Matchmaker ticket: " << ticket.ticket << std::endl;
};

int32_t minCount = 2;
int32_t maxCount = 4;
string query = "+properties.skill:>=13 +properties.skill:<=17";
NStringDoubleMap numericProperties;

numericProperties.emplace("skill", 15.0);

rtClient->addMatchmaker(minCount, maxCount, query, numericProperties, successCallback);
Client
1
2
3
4
5
6
7
8
9
String query = "+properties.skill:>=13 +properties.skill:<=17";
int minCount = 2;
int maxCount = 4;

Map<String, Double> numericProperties = new HashMap<String, Double>() {{
    put("skill", 15.0);
}};

MatchmakerTicket matchmakerTicket = socket.addMatchmaker(query, minCount, maxCount, numericProperties).get();
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var query = "+properties.skill:>=13 +properties.skill:<=17"
var numeric_properties = { "skill": 15 }

var matchmaker_ticket : NakamaRTAPI.MatchmakerTicket = yield(
    socket.add_matchmaker_async(query, 2, 4, numeric_properties),
    "completed"
)

if matchmaker_ticket.is_exception():
    print("An error occurred: %s" % matchmaker_ticket)
    return

print("Got ticket: %s" % [matchmaker_ticket])

Code snippet for this language Defold has not been found. Please choose another language to show equivalent examples.
Code snippet for this language cURL has not been found. Please choose another language to show equivalent examples.
Code snippet for this language REST has not been found. Please choose another language to show equivalent examples.

지역 선호도 부스팅 #

이 예에서 우리 플레이어는 유럽 지역에 있으며 우선 같은 지역의 다른 플레이어와 매치메이킹하고 싶으며 그 다음으로 아시아 및 아프리카 지역을 원합니다:

Client
1
2
3
4
5
6
7
8
9
const query = "properties.region:europe^3 properties.region:asia^2 properties.region:africa";
const minCount = 2;
const maxCount = 4;

const stringProperties = {
  region: "europe"
};

var ticket = await socket.addMatchmaker(query, minCount, maxCount, stringProperties);
Client
1
2
3
4
5
6
7
var query = "properties.region:europe^3 properties.region:asia^2 properties.region:africa";

var stringProperties = new Dictionary<string, string>() {
    {"region", "europe"}
};

var matchmakerTicket = await socket.AddMatchmakerAsync(query, 2, 4, stringProperties);
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
auto successCallback = [](const NMatchmakerTicket& ticket)
{
    std::cout << "Matchmaker ticket: " << ticket.ticket << std::endl;
};

int32_t minCount = 2;
int32_t maxCount = 4;
string query = "properties.region:europe^3 properties.region:asia^2 properties.region:africa";
NStringMap stringProperties;

stringProperties.emplace("region", "europe");

rtClient->addMatchmaker(minCount, maxCount, query, stringProperties, successCallback);
Client
1
2
3
4
5
6
7
8
9
String query = "properties.region:europe^3 properties.region:asia^2 properties.region:africa";
int minCount = 2;
int maxCount = 4;

Map<String, String> stringProperties = new HashMap<String, String>() {{
    put("region", "europe");
}};

MatchmakerTicket matchmakerTicket = socket.addMatchmaker(query, minCount, maxCount, stringProperties).get();
Client
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var query = "properties.region:europe^3 properties.region:asia^2 properties.region:africa"
var string_properties = { "region": "europe" }

var matchmaker_ticket : NakamaRTAPI.MatchmakerTicket = yield(
    socket.add_matchmaker_async(query, 2, 4, string_properties),
    "completed"
)

if matchmaker_ticket.is_exception():
    print("An error occurred: %s" % matchmaker_ticket)
    return

print("Got ticket: %s" % [matchmaker_ticket])

Code snippet for this language Defold has not been found. Please choose another language to show equivalent examples.
Code snippet for this language cURL has not been found. Please choose another language to show equivalent examples.
Code snippet for this language REST has not been found. Please choose another language to show equivalent examples.

Related Pages