Skip to content

Commit c3b9544

Browse files
zyromofirouz
authored andcommitted
Allow authoritative match join attempts to carry metadata. Improve sample lua modules.
1 parent c966b2e commit c3b9544

14 files changed

+193
-154
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ The format is based on [keep a changelog](http://keepachangelog.com) and this pr
77
### Added
88
- More flexible query-based filter when listing realtime multiplayer matches.
99
- Runtime function to batch get groups by group ID.
10+
- Allow authoritative match join attempts to carry metadata from the client.
1011

1112
### Changed
1213
- Improved cancellation of ongoing work when clients disconnect.

data/modules/clientrpc.lua

+8-2
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,14 @@ local function send_stream_data(context, payload)
6565
end
6666
nk.register_rpc(send_stream_data, "clientrpc.send_stream_data")
6767

68-
local function create_authoritative_match(_context, _payload)
69-
local match_id = nk.match_create("match", { debug = true })
68+
local function create_authoritative_match(_context, payload)
69+
local decoded = nk.json_decode(payload)
70+
local params = {
71+
debug = (decoded and decoded.debug) or true,
72+
label = (decoded and decoded.label)
73+
}
74+
75+
local match_id = nk.match_create("match", params)
7076
return nk.json_encode({ match_id = match_id })
7177
end
7278
nk.register_rpc(create_authoritative_match, "clientrpc.create_authoritative_match")

data/modules/match.lua

+9-1
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,21 @@ Presence is the user attempting to join the match. Format:
8686
node: "name of the Nakama node the user is connected to"
8787
}
8888
89+
Metadata is an optional set of arbitrary key-value pairs received from the client. These may contain information
90+
the client wishes to supply to the match handler in order to process the join attempt, for example: authentication or
91+
match passwords, client version information, preferences etc. Format:
92+
{
93+
key: "value"
94+
}
95+
8996
Expected return these values (all required) in order:
9097
1. An (optionally) updated state. May be any non-nil Lua term, or nil to end the match.
9198
2. Boolean true if the join attempt should be allowed, false otherwise.
9299
--]]
93-
local function match_join_attempt(context, dispatcher, tick, state, presence)
100+
local function match_join_attempt(context, dispatcher, tick, state, presence, metadata)
94101
if state.debug then
95102
print("match join attempt:\n" .. du.print_r(presence))
103+
print("match join attempt metadata:\n" .. du.print_r(metadata))
96104
end
97105
return state, true
98106
end

data/modules/p2prelayer.lua

+4
Original file line numberDiff line numberDiff line change
@@ -52,4 +52,8 @@ function M.match_loop(context, dispatcher, tick, state, messages)
5252
end
5353
end
5454

55+
function M.match_terminate(context, dispatcher, tick, state, grace_seconds)
56+
return nil
57+
end
58+
5559
return M

rtapi/realtime.pb.go

+149-137
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rtapi/realtime.proto

+2
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,8 @@ message MatchJoin {
275275
// A matchmaking result token.
276276
string token = 2;
277277
}
278+
// An optional set of key-value metadata pairs to be passed to the match handler, if any.
279+
map<string, string> metadata = 3;
278280
}
279281

280282
// Leave a realtime match.

runtime/runtime.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ type MatchDispatcher interface {
228228

229229
type Match interface {
230230
MatchInit(ctx context.Context, logger *log.Logger, db *sql.DB, nk NakamaModule, params map[string]interface{}) (interface{}, int, string)
231-
MatchJoinAttempt(ctx context.Context, logger *log.Logger, db *sql.DB, nk NakamaModule, dispatcher MatchDispatcher, tick int64, state interface{}, presence Presence) (interface{}, bool, string)
231+
MatchJoinAttempt(ctx context.Context, logger *log.Logger, db *sql.DB, nk NakamaModule, dispatcher MatchDispatcher, tick int64, state interface{}, presence Presence, metadata map[string]string) (interface{}, bool, string)
232232
MatchJoin(ctx context.Context, logger *log.Logger, db *sql.DB, nk NakamaModule, dispatcher MatchDispatcher, tick int64, state interface{}, presences []Presence) interface{}
233233
MatchLeave(ctx context.Context, logger *log.Logger, db *sql.DB, nk NakamaModule, dispatcher MatchDispatcher, tick int64, state interface{}, presences []Presence) interface{}
234234
MatchLoop(ctx context.Context, logger *log.Logger, db *sql.DB, nk NakamaModule, dispatcher MatchDispatcher, tick int64, state interface{}, messages []MatchData) interface{}

sample_go_module/sample.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,9 @@ func (m *Match) MatchInit(ctx context.Context, logger *log.Logger, db *sql.DB, n
8282
return state, tickRate, label
8383
}
8484

85-
func (m *Match) MatchJoinAttempt(ctx context.Context, logger *log.Logger, db *sql.DB, nk runtime.NakamaModule, dispatcher runtime.MatchDispatcher, tick int64, state interface{}, presence runtime.Presence) (interface{}, bool, string) {
85+
func (m *Match) MatchJoinAttempt(ctx context.Context, logger *log.Logger, db *sql.DB, nk runtime.NakamaModule, dispatcher runtime.MatchDispatcher, tick int64, state interface{}, presence runtime.Presence, metadata map[string]string) (interface{}, bool, string) {
8686
if state.(*MatchState).debug {
87-
logger.Printf("match join attempt username %v user_id %v session_id %v node %v", presence.GetUsername(), presence.GetUserId(), presence.GetSessionId(), presence.GetNodeId())
87+
logger.Printf("match join attempt username %v user_id %v session_id %v node %v with metadata %v", presence.GetUsername(), presence.GetUserId(), presence.GetSessionId(), presence.GetNodeId(), metadata)
8888
}
8989

9090
return state, true, ""

server/match_handler.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -230,14 +230,14 @@ func loop(mh *MatchHandler) {
230230
mh.tick++
231231
}
232232

233-
func JoinAttempt(resultCh chan *MatchJoinResult, userID, sessionID uuid.UUID, username, node string) func(mh *MatchHandler) {
233+
func JoinAttempt(resultCh chan *MatchJoinResult, userID, sessionID uuid.UUID, username, node string, metadata map[string]string) func(mh *MatchHandler) {
234234
return func(mh *MatchHandler) {
235235
if mh.stopped.Load() {
236236
resultCh <- &MatchJoinResult{Allow: false}
237237
return
238238
}
239239

240-
state, allow, reason, err := mh.core.MatchJoinAttempt(mh.tick, mh.state, userID, sessionID, username, node)
240+
state, allow, reason, err := mh.core.MatchJoinAttempt(mh.tick, mh.state, userID, sessionID, username, node, metadata)
241241
if err != nil {
242242
mh.Stop()
243243
mh.logger.Warn("Stopping match after error from match_join_attempt execution", zap.Int64("tick", mh.tick), zap.Error(err))

server/match_registry.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ type MatchRegistry interface {
9797
Stop(graceSeconds int) chan struct{}
9898

9999
// Pass a user join attempt to a match handler. Returns if the match was found, if the join was accepted, a reason for any rejection, and the match label.
100-
JoinAttempt(id uuid.UUID, node string, userID, sessionID uuid.UUID, username, fromNode string) (bool, bool, string, string)
100+
JoinAttempt(id uuid.UUID, node string, userID, sessionID uuid.UUID, username, fromNode string, metadata map[string]string) (bool, bool, string, string)
101101
// Notify a match handler that one or more users have successfully joined the match.
102102
// Expects that the caller has already determined the match is hosted on the current node.
103103
Join(id uuid.UUID, presences []*MatchPresence)
@@ -422,7 +422,7 @@ func (r *LocalMatchRegistry) Stop(graceSeconds int) chan struct{} {
422422
return r.stoppedCh
423423
}
424424

425-
func (r *LocalMatchRegistry) JoinAttempt(id uuid.UUID, node string, userID, sessionID uuid.UUID, username, fromNode string) (bool, bool, string, string) {
425+
func (r *LocalMatchRegistry) JoinAttempt(id uuid.UUID, node string, userID, sessionID uuid.UUID, username, fromNode string, metadata map[string]string) (bool, bool, string, string) {
426426
if node != r.node {
427427
return false, false, "", ""
428428
}
@@ -437,7 +437,7 @@ func (r *LocalMatchRegistry) JoinAttempt(id uuid.UUID, node string, userID, sess
437437
}
438438

439439
resultCh := make(chan *MatchJoinResult, 1)
440-
if !mh.QueueCall(JoinAttempt(resultCh, userID, sessionID, username, fromNode)) {
440+
if !mh.QueueCall(JoinAttempt(resultCh, userID, sessionID, username, fromNode, metadata)) {
441441
// The match call queue was full, so will be closed and therefore can't be joined.
442442
return true, false, "", ""
443443
}

server/pipeline_match.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ func (p *Pipeline) matchJoin(logger *zap.Logger, session Session, envelope *rtap
173173
// The user is not yet part of the match, attempt to join.
174174
if mode == StreamModeMatchAuthoritative {
175175
// If it's an authoritative match, ask the match handler if it will allow the join.
176-
found, allow, reason, l = p.matchRegistry.JoinAttempt(matchID, node, session.UserID(), session.ID(), username, p.node)
176+
found, allow, reason, l = p.matchRegistry.JoinAttempt(matchID, node, session.UserID(), session.ID(), username, p.node, incoming.Metadata)
177177
}
178178
if !found {
179179
// Match did not exist.

server/runtime.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ func (e RuntimeExecutionMode) String() string {
215215

216216
type RuntimeMatchCore interface {
217217
MatchInit(params map[string]interface{}) (interface{}, int, string, error)
218-
MatchJoinAttempt(tick int64, state interface{}, userID, sessionID uuid.UUID, username, node string) (interface{}, bool, string, error)
218+
MatchJoinAttempt(tick int64, state interface{}, userID, sessionID uuid.UUID, username, node string, metadata map[string]string) (interface{}, bool, string, error)
219219
MatchJoin(tick int64, state interface{}, joins []*MatchPresence) (interface{}, error)
220220
MatchLeave(tick int64, state interface{}, leaves []*MatchPresence) (interface{}, error)
221221
MatchLoop(tick int64, state interface{}, inputCh chan *MatchDataMessage) (interface{}, error)

server/runtime_go_match_core.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -99,15 +99,15 @@ func (r *RuntimeGoMatchCore) MatchInit(params map[string]interface{}) (interface
9999
return state, tickRate, label, nil
100100
}
101101

102-
func (r *RuntimeGoMatchCore) MatchJoinAttempt(tick int64, state interface{}, userID, sessionID uuid.UUID, username, node string) (interface{}, bool, string, error) {
102+
func (r *RuntimeGoMatchCore) MatchJoinAttempt(tick int64, state interface{}, userID, sessionID uuid.UUID, username, node string, metadata map[string]string) (interface{}, bool, string, error) {
103103
presence := &MatchPresence{
104104
Node: node,
105105
UserID: userID,
106106
SessionID: sessionID,
107107
Username: username,
108108
}
109109

110-
newState, allow, reason := r.match.MatchJoinAttempt(r.ctx, r.stdLogger, r.db, r.nk, r, tick, state, presence)
110+
newState, allow, reason := r.match.MatchJoinAttempt(r.ctx, r.stdLogger, r.db, r.nk, r, tick, state, presence, metadata)
111111
return newState, allow, reason, nil
112112
}
113113

server/runtime_lua_match_core.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -233,13 +233,18 @@ func (r *RuntimeLuaMatchCore) MatchInit(params map[string]interface{}) (interfac
233233
return state, rateInt, labelStr, nil
234234
}
235235

236-
func (r *RuntimeLuaMatchCore) MatchJoinAttempt(tick int64, state interface{}, userID, sessionID uuid.UUID, username, node string) (interface{}, bool, string, error) {
236+
func (r *RuntimeLuaMatchCore) MatchJoinAttempt(tick int64, state interface{}, userID, sessionID uuid.UUID, username, node string, metadata map[string]string) (interface{}, bool, string, error) {
237237
presence := r.vm.CreateTable(0, 4)
238238
presence.RawSetString("user_id", lua.LString(userID.String()))
239239
presence.RawSetString("session_id", lua.LString(sessionID.String()))
240240
presence.RawSetString("username", lua.LString(username))
241241
presence.RawSetString("node", lua.LString(node))
242242

243+
metadataTable := r.vm.CreateTable(0, len(metadata))
244+
for k, v := range metadata {
245+
metadataTable.RawSetString(k, lua.LString(v))
246+
}
247+
243248
// Execute the match_join_attempt call.
244249
r.vm.Push(LSentinel)
245250
r.vm.Push(r.joinAttemptFn)
@@ -248,8 +253,9 @@ func (r *RuntimeLuaMatchCore) MatchJoinAttempt(tick int64, state interface{}, us
248253
r.vm.Push(lua.LNumber(tick))
249254
r.vm.Push(state.(lua.LValue))
250255
r.vm.Push(presence)
256+
r.vm.Push(metadataTable)
251257

252-
err := r.vm.PCall(5, lua.MultRet, nil)
258+
err := r.vm.PCall(6, lua.MultRet, nil)
253259
if err != nil {
254260
return nil, false, "", err
255261
}

0 commit comments

Comments
 (0)