Supporting relayed and authoritative modes at the same time via matchmaking?

I am trying to understand the best design approach for potentially supporting Relayed and Authoritative multi-player at the same time. The Matchmaker Documentation provides an example function (below) to load the player into a known authoritative game mode (pingpong) in this instance.

func MakeMatch(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, entries []runtime.MatchmakerEntry) (string, error) {
    for _, e := range entries {
        logger.Info("Matched user '%s' named '%s'", e.GetPresence().GetUserId(), e.GetPresence().GetUsername())

        for k, v := range e.GetProperties() {
            logger.Info("Matched on '%s' value '%v'", k, v)
        }
    }

    matchId, err := nk.MatchCreate(ctx, "pingpong", map[string]interface{}{"invited": entries})

    if err != nil {
        return "", err
    }

    return matchId, nil
}

// Register as matchmaker matched hook, this call should be in InitModule.
if err := initializer.RegisterMatchmakerMatched(MakeMatch); err != nil {
    logger.Error("Unable to register: %v", err)
    return err
}

Assuming that users correctly query for (and provide the necessary properties) to only match on a particular game mode (as an example) can I safely call nk.MatchCreate(ctx, "") to get the default relayed implementation, otherwise calling the provided module name for a known game-mode?

An example (not great, but illustrative idea being)

func MakeMatch(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, entries []runtime.MatchmakerEntry) (string, error) {
	var authoritative bool
	var moduleName string = ""

	for _, e := range entries {
		logger.Info("Matched user '%s' named '%s'", e.GetPresence().GetUserId(), e.GetPresence().GetUsername())

		for k, v := range e.GetProperties() {
			logger.Info("Matched on '%s' value '%v'", k, v)

			if !authoritative && v == "authed_match" {
				authoritative = true
				moduleName = "authed_match"
			}
		}
	}

	matchId, err := nk.MatchCreate(ctx, moduleName, nil)

	if err != nil {
		return "", err
	}

	return matchId, nil
}

The IMatch object returned correctly specifies the authoritative flag in both scenarios, but it does have a match id for both match types. According to the Matchmaker Documentation a non-authoritative server should return a token and not a matchId. Is this an error in the demo adapted above or my misunderstanding of the docs (or both?)

EDIT: Alternatively is this better suited to a Before hook of some kind?

@scottmk you’re correct that the MatchmakerMatched hook can return both a matchId (authoritative) or a token (relayed), but you need to rework your logic slightly.

If you want to create an authoritative match you’d return the matchId resulting from nk.MatchCreate(ctx, moduleName, nil), mind that this function does not accept an empty string as a moduleName, so you’d only invoke it only if you wish the created match to be authoritative.

If you’d like to create a relayed match, just return an empty string as the return value of MakeMatch and a token will be provided to the clients.

So essentially I can just do something like this (again hacky, proof of concept code)?

func MakeMatch(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, entries []runtime.MatchmakerEntry) (string, error) {
	var authoritative bool
	var moduleName string = ""

	for _, e := range entries {
		logger.Info("Matched user '%s' named '%s'", e.GetPresence().GetUserId(), e.GetPresence().GetUsername())

		for k, v := range e.GetProperties() {
			logger.Info("Matched on '%s' value '%v'", k, v)

			if !authoritative && v == "authed_match" {
				authoritative = true
				moduleName = "authed_match"
			}
		}
	}

	if !authoritative {
		return "", nil
	}

	matchId, err := nk.MatchCreate(ctx, moduleName, nil)

	if err != nil {
		return "", err
	}

	return matchId, nil
}

This still seems to return an Id how do I know if the returned id is a token or not? IMatch doesn’t have a Token property. Otherwise this seems to work thanks!

EDIT: It appears that if it ends in .nakama it’s authoritative, otherwise it is relayed?

Your code looks good to me and that’s correct, as you can also verify in the Authoritative column of the dashboard screenshot.