How to link chat and match together?

Is there any conventional way to link match and chat channel together?
Or somehow to open direct chat channel along with a new or existing match?

Hi @yudi-xiao. I have a few questions about your question :slight_smile:

Is there any conventional way to link match and chat channel together?

  1. Should these chat messages sent over the channel be persistent or only exist while the match is active?
  2. Do you use the authoritative multiplayer engine or the relayed multiplayer in the server?
  3. How many users will be in the chat channel? Is it the same number who’re currently connected to the match?

Thanks for the reply,

  1. Chat message need to be persistent on the server.
  2. We tried relayed multiplayer in the server (I guess by relayed multiplayer you mean this right?)
  3. Currently, we only need to consider direct chat so yes the number of users should be the same.

Thanks for the details.

  1. We tried relayed multiplayer in the server (I guess by relayed multiplayer you mean this right?)

Yep that was the feature I meant when I referred to relayed multiplayer. The reason I asked was if you had a match handler (with the authoritative multiplayer engine) and you didn’t need to persist chat messages then you could just send those messages over the match with a specific opcode.

For your use case where you need a fully persistent chat channel to run alongside the match where players are connect the simplest approach right now would be to signal the clients to join a chat room who’s name is the same as the match ID. This way all players know from the game clients which chat channel to join after they’ve successfully joined a match.

I’ve considered this way, but the tricky part is we want to use chat channel as the unique id, not the match id. So that each time 2(or more) users start(or continue) a chatting session, they could check if a match has been created by the server, it does then connect to the match or create a new one otherwise. Also, we need to consider when all users have disconnected from chat/match and the match become expired.
Is there anything that can save this information in the chat channel?
And I’m not sure if I need to write something like RPC function in the server to handle this behaviour?

I’ll assume you’ve already set up a chat channel for the users, perhaps by having them join the same chat room. We can tie this channel to a match by having a “find or create match” RPC function that will either give the user an existing match ID to join, or create a new match if that channel didn’t already have one running.

This of course means you’ll want to use the authoritative multiplayer feature to maintain match state and information you can use to look up the match.

You’ll need 2 runtime scripts. A rpc.lua:

local nk = require("nakama")

local function list_all(context, payload)
  -- expects input to be in the format: {"channel_id": "some room name"}
  local input = nk.json_decode(payload)
  local channel_id = input["channel_id"]

  local matches = nk.match_list(1, true, channel_id)
  if #matches == 1 then
    -- already have a match running for this channel
    return matches[1]
  end

  -- match for this channel wasn't running, start one now
  return nk.match_create("match", {channel_id = channel_id})
end

And a match handler we’ll call match.lua:

local nk = require("nakama")

local M = {}

function M.match_init(context, setupstate)
  local gamestate = {
    channel_id = setupstate["channel_id"]
  }
  local tickrate = 1
  -- put the channel identifier in the match label so other players can find it
  local label = setupstate["channel_id"]
  return gamestate, tickrate, label
end

function M.match_join_attempt(context, dispatcher, tick, state, presence, metadata)
  -- check that only users in that chat channel can join the match by checking
  -- if the user attempting to join has a presence in the chat channel's stream
  local stream_id = { mode = 2, label = state.channel_id }
  local meta = nk.stream_user_get(presence.user_id, presence.session_id, stream_id)
  local accept_user = meta ~= nil
  return state, accept_user
end

function M.match_join(context, dispatcher, tick, state, presences)
  return state
end

function M.match_leave(context, dispatcher, tick, state, presences)
  return state
end

function M.match_loop(context, dispatcher, tick, state, messages)
  -- match logic here
  return state
end

function M.match_terminate(context, dispatcher, tick, state, grace_seconds)
  return nil
end

return M

You can learn more about streams in the advanced documentation here.

1 Like

Have a syntax error at ‘=’ in

return nk.match_create("match", {"channel_id" = channel_id})

, i assuming changing it to

return nk.match_create("match", {["channel_id"] = channel_id})

should fix it.

Yeah that should work too, but I’ve updated the example with an alternative syntax that should be fine.