Retrieve initial state params using match_list

Hello,
I am storing initial parameters of server authorative match in the match’s state.
{

initst={params.initst}

}

However, when finding the match using match_list,
the state is not returned. Instead, returns match_id, authoriative flag, and label (the docs do not appear to describe the schema of the match_list returned object, so above is just my understanding of what I see during the debugging)

Label field, from my understanding, can only be 256 chars long.
And that’s not enough length to represent my params.initst (I have a function that can serialize a flat json object into key=val pairs just so that I can put anything in the label, but the allowed length of the label is not enough).

Therefore, wanted to ask what would be a recommended design pattern for the cases where I would like to retrieve a portion or full json object representing match state via match_list

Here is the match_list invocation:

local matches = nk.match_list(limit, isauthoritative, nil, min_size, max_size,nil)

Here is my match_init that captures the initst
and stores into match state (initparm is currently empty, just relying on initst custome field, at the moment) :

local function match_init(context, params)
  local state = {
    debug = (params and params.debug) or false,
    initparm=params.initparm,
    initst = params.initst
  }
  if state.debug then
    print("match init context:\n" .. du.print_r(context) .. "match init params:\n" .. du.print_r(params))
  end

  local tick_rate = 1 
  return state, tick_rate, "add_useful_256chars_label_later"
end

I am running latest version of Nakama server (as of today) built from tip of the source tree.

I read somewhere, (may be somewhere in the comments), that there was an effort to migrate from label as string, to using label as json object . This would, potentially, work for what I needed, but when trying to return {…} rather than string from match_init, I got an error saying that 3rd return object must be string.

@vladislav You can already return JSON data as the match label, after all a JSON string is just a subset of all strings for validation purposes. In your Lua code you might return this from match_init:

[...]
return state, tick_rate, nk.json_encode({ foo = "bar", baz = 123 })
[...]

The server will index and make the label searchable as you’d expect. Can you point me to where you found the 256 character limit mentioned? That’s likely an outdated documentation section or code example. The limit is 2048 characters (2 KB) which I think is useful for most cases.

As far as your original point - no, it’s not possible to read/return the match state or any portion of it outside the match handler. The label is the match’s way of communicating with the match listing system. In most cases you would put a subset of the match state in the label: player skill level, map being played, if the game is in progress or still waiting for more players before it starts etc. Whatever is appropriate for your use case.

The match state (or a significant part of it) is usually sent to clients when they join the match to “sync” them, then as the match progresses you would send small state deltas containing changes as they happen. This will make sure the clients have a constantly updating view of the server state.

Thank you. I understand now.
The label can be a json string, and that’s compatible with Bleve search.

With regards where I saw 256 chars limit, I think it was
https://heroiclabs.com/docs/gameplay-multiplayer-server-multiplayer/
But I see it is changed there now to 2k.

Would like to ask, if possible, for one more clarification/confirmation.

When I set the label to be serialized json string (which includes a member ctrlUrl), I cannot seem to find the created match using the query string:

queryOnLabelFld=+label.ctrlUrl:http://10.0.1.22:11555
local matches = nk.match_list(limit, isauthoritative, queryOnLabelFld, min_size, max_size, nil)

Is there a different syntax to use in the case of a label being json string ?( or perhaps my expectations are off of how this should work)

The label is indexed using bleve. As the documentation indicates you’ll need to escape your query string if it contains certain special characters.

In your case the query should be something like:

local queryOnLabelField = "+label.ctrlUrl:http\\:\\/\\/10.0.1.22\\:11555"
local matches = nk.match_list(limit, isauthoritative, nil, min_size, max_size, queryOnLabelField)

Note also you’ll need to pass the query as the last parameter to the nk.match_list operation. The field you were trying to use before is a simple filter only, useful for exact matches of the whole label value. Complex querying is done through the last parameter.

@zyro Thank you again for your help.
I feel like I should have caught my bleve escape problem, myself. Thank you for being patient with me.

The explanation that the 3rd parameter in match_list is only for matching the full label as a simple string, is also very helpful, I did not understand, for some reason, the difference between listing by ‘label’ vs listing ‘by query’ )

Also, in case this may be of use for somebody, below is a function esc4bleve that will escape an arbitrary string meant to be for Bleve query.

-- bleve escape start
-- Bleve Spec: https://blevesearch.com/docs/Query-String-Query/
local bleveSpec__EscStr=[[+-=&|><!(){}[]^\"~*?:/ ]]
local bleveSpec__EscSymbol=[[\]]

--special chars in Lua gsub/match patters and their escaped replacement
local luaPatternSpecialCharsTb={
["("]="%",
[")"]="%)",
["%"]="%%",
["."]="%.",
["+"]="%+",
["-"]="%-",
["*"]="%*",
["["]="%[",
["]"]="%]",-- luapedia is missing this https://lua.programmingpedia.net/en/tutorial/5829/pattern-matching
["?"]="%?",
["^"]="%^",
["$"]= "%$"}

-- construct a clean pattern to find all Bleve-escapable chars 
local patternToFind=bleveSpec__EscStr:gsub(".",luaPatternSpecialCharsTb)
-- we need a set, so that gsub uses the pattern as 'or this' or that
local patternAsSet='['..patternToFind..']'

-- now we are bulding a table to tell gsub to
-- how to replace the found escapable charcters
-- For Bleve we replacing every escapable character with
-- \\+the_character
-- so :  will be replaced with \\: and so on
local escReplacementTb={}
for c in string.gmatch(bleveSpec__EscStr,".") do --iterate over
     escReplacementTb[c]=bleveSpec__EscSymbol..c
end

-- now the actual function. It should be reasonably fast even on very large strings
-- due to all the prep we have done globally, we are invoking gsub only once
local function esc4bleve(str)
    -- use gsub's ability to use table to find substituion for every pattern match
    local res= string.gsub(str,patternAsSet, escReplacementTb)
    --print("esc4bleve str= "..str.."  res= "..res)
    return res
end
-- beleve escape end
1 Like