So I create matches manually instead of using the match maker. It seems the built in match maker is really slow and it gives me no insight into what it does and why it takes a long time.
Matches are created like this:
limit := 5
authoritative := true
label := ""
minSize := 0 //matchMode.PlayersMin
maxSize := 10 //matchMode.PlayersMax
query := "+mode:" + strconv.Itoa(matchMode.Ident)
matches, err := nk.MatchList(ctx, limit, authoritative, label, &minSize, &maxSize, query)
if err != nil {
log.Printf("failed to list matches: %v", err)
return "", err
}
log.Printf("query '%s' found %d matches", query, len(matches))
for _, match := range matches {
log.Printf("found match: %v", match)
}
var matchId string
if len(matches) == 0 {
var params = map[string]interface{}{"mode": matchMode.Ident}
if matchId, err = nk.MatchCreate(ctx, "xxx", params); err != nil {
return "", err
}
log.Printf("created a new match: %s", matchId)
} else {
log.Printf("using old match")
matchId = matches[0].MatchId
}
...
A new match is created if there’s no old matching match. I see that our callbacks for setting up a match handler is created and the match loop starts to run, so the match seems to be valid and fine. The next time the same code is executed the query +mode:X where X is a number that basically indicates the exact number of players wanted. The created matches have that property set and the query requires it. However MatchList never finds anything matching. If I set the query to "" it does find the existing match.
Is there something that I’ve fundamentally missed about how the queries and/or properties work? When using the match maker the same query does seem to find matches. The code above is pretty much copied from the docs, except that there’s a small bug as MatchList wants pointers for &minSize, &maxSize.
Is there something that I’ve fundamentally missed about how the queries and/or properties work? When using the match maker the same query does seem to find matches. The code above is pretty much copied from the docs, except that there’s a small bug as MatchList wants pointers for &minSize, &maxSize .
How are you creating the Match (match handler) and how are you persisting the match label? Remember it must be a JSON literal object:
You can only use search queries if you use a JSON value for the match label. If you instead use a simple value (e.g. "team-deathmatch" ) you can only perform an exact match using the label parameter in the Match Listings API.
I would say I don’t even query for the label as it’s set to "". So it should work? The docs for the match label don’t really say what it should be used for, other than that it’s a label. I’ve seen no reason to use it and thus use "". I assume this is a case where the docs could use some improvement.
does not use the label either. Our MatchInit handler sets up an own MatchState struct and returns that along with a tick rate of 10 and an empty label.
Yep we ought to improve this section of docs (cc @Sean )
If you set the match label (in the match handler) to a non-json object (like what the examples have shown), then you can only do exact queries using the label field in the MatchListing API.
However, if you set the label to a JSON object in the match handler, then Nakama will index the label and make it ready for search, and you can use the query field in the MatchListing API.
Ok, so what is the purpose of the label? Is it only to enable queries on the properties? I mean, can I just set it to "foo":42 and be done with it and then use the property queries to find matches?
2021/12/03 14:04:15.222594 match.go:58: MatchInit: match dfd432f5-65f8-4290-a53b-71d58aa548ec initialized, label: {"foo":42}
...
2021/12/03 14:04:17.374009 battle_api.go:61: query 'mode:2' found 0 matches
Note that mode:2 is even optional, it should certainly have found the created match. Or is the label somehow significant for MatchList too? I leave it as empty in order to find matches with any label.
Ok, so what is the purpose of the label? Is it only to enable queries on the properties? I mean, can I just set it to "foo":42 and be done with it and then use the property queries to find matches?
The purpose of the label field in the MatchListing API is to do exact query look up without indexing.
Hm, no, that doesn’t work.
Your match label is {"foo": 42} whilst your query is mode:2 - this will never match.
Or is the label somehow significant for MatchList too
Yes the match label you set in the match handler directly affects the query you are performing in the MatchListing call.
Uses label := "skill=100-150" as an argument to MatchList. Does this mean that the label is also a form of query and this would list matches created with labels skill:111 and skill:142?
Uses label := "skill=100-150" as an argument to MatchList . Does this mean that the label is also a form of query and this would list matches created with labels skill:111 and skill:142 ?
Yes if that label was not a string but a JSON literal like:
{"skill": 100}
Then you can use the query field in the MatchList API.
Even more confusing… Isn’t my query parameter supposed to match things I set in the parameters for MatchCreate? Or are those parameters only for my own use? Let me test and see.
AFAIK there are no “JSON literals” in Go, but I could be wrong here. The above json.Marshal should create the required JSON.
I feel so extremely stupid when I can’t grok how this is supposed to work. Granted, I’m far from the sharpest tool in the shed, but this shouldn’t be impossible.