Commit f16e0eb4 authored by Simon Esposito's avatar Simon Esposito Committed by Andrei Mihu
Browse files

Add go runtime matchmaker custom matching fn

parent 43699992
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -284,8 +284,6 @@ func (m *LocalMatchmaker) OnMatchedEntries(fn func(entries [][]*MatchmakerEntry)
	m.matchedEntriesFn = fn
}

var customMatchingFn func([][]*MatchmakerEntry) [][]*MatchmakerEntry

func (m *LocalMatchmaker) Process() {
	startTime := time.Now()

@@ -305,8 +303,8 @@ func (m *LocalMatchmaker) Process() {
	}

	var matchedEntries [][]*MatchmakerEntry
	if customMatchingFn != nil {
		matchedEntries = m.processCustom(customMatchingFn)
	if m.runtime.matchmakerCustomMatchingFunction != nil {
		matchedEntries = m.processCustom()
	} else {
		matchedEntries = m.processDefault()
	}
+2 −3
Original line number Diff line number Diff line
@@ -334,7 +334,7 @@ func (m *LocalMatchmaker) processDefault() [][]*MatchmakerEntry {
	return matchedEntries
}

func (m *LocalMatchmaker) processCustom(customMatchingFn func([][]*MatchmakerEntry) [][]*MatchmakerEntry) [][]*MatchmakerEntry {
func (m *LocalMatchmaker) processCustom() [][]*MatchmakerEntry {
	matchedEntries := make([][]*MatchmakerEntry, 0, 5)

	var threshold bool
@@ -574,8 +574,7 @@ func (m *LocalMatchmaker) processCustom(customMatchingFn func([][]*MatchmakerEnt
	}

	// Allow the custom function to determine which of the matches should be formed. All others will be discarded.
	// TODO replace function.
	matchedEntries = customMatchingFn(matchedEntries)
	matchedEntries = m.runtime.matchmakerCustomMatchingFunction(m.ctx, matchedEntries)

	ticketsToDelete := make(map[string]struct{}, len(matchedEntries))
	finalMatchedEntries := make([][]*MatchmakerEntry, 0, len(matchedEntries))
+17 −3
Original line number Diff line number Diff line
@@ -209,6 +209,7 @@ type (
	RuntimeAfterGetSubscriptionFunction                    func(ctx context.Context, logger *zap.Logger, userID, username string, vars map[string]string, expiry int64, clientIP, clientPort string, out *api.ValidatedSubscription, in *api.GetSubscriptionRequest) error

	RuntimeMatchmakerMatchedFunction        func(ctx context.Context, entries []*MatchmakerEntry) (string, bool, error)
	RuntimeMatchmakerCustomMatchingFunction func(ctx context.Context, matches [][]*MatchmakerEntry) [][]*MatchmakerEntry

	RuntimeMatchCreateFunction       func(ctx context.Context, logger *zap.Logger, id uuid.UUID, node string, stopped *atomic.Bool, name string) (RuntimeMatchCore, error)
	RuntimeMatchDeferMessageFunction func(msg *DeferredMessage) error
@@ -240,6 +241,7 @@ const (
	RuntimeExecutionModeAfter
	RuntimeExecutionModeMatch
	RuntimeExecutionModeMatchmaker
	RuntimeExecutionModeMatchmakerCustomMatching
	RuntimeExecutionModeMatchCreate
	RuntimeExecutionModeTournamentEnd
	RuntimeExecutionModeTournamentReset
@@ -266,6 +268,8 @@ func (e RuntimeExecutionMode) String() string {
		return "match"
	case RuntimeExecutionModeMatchmaker:
		return "matchmaker"
	case RuntimeExecutionModeMatchmakerCustomMatching:
		return "matchmaker_custom_matching"
	case RuntimeExecutionModeMatchCreate:
		return "match_create"
	case RuntimeExecutionModeTournamentEnd:
@@ -498,6 +502,7 @@ type Runtime struct {
	afterReqFunctions  *RuntimeAfterReqFunctions

	matchmakerMatchedFunction        RuntimeMatchmakerMatchedFunction
	matchmakerCustomMatchingFunction RuntimeMatchmakerCustomMatchingFunction

	tournamentEndFunction                  RuntimeTournamentEndFunction
	tournamentResetFunction                RuntimeTournamentResetFunction
@@ -626,7 +631,7 @@ func NewRuntime(ctx context.Context, logger, startupLogger *zap.Logger, db *sql.

	matchProvider := NewMatchProvider()

	goModules, goRPCFns, goBeforeRtFns, goAfterRtFns, goBeforeReqFns, goAfterReqFns, goMatchmakerMatchedFn, goTournamentEndFn, goTournamentResetFn, goLeaderboardResetFn, goPurchaseNotificationAppleFn, goSubscriptionNotificationAppleFn, goPurchaseNotificationGoogleFn, goSubscriptionNotificationGoogleFn, allEventFns, goMatchNamesListFn, err := NewRuntimeProviderGo(ctx, logger, startupLogger, db, protojsonMarshaler, config, version, socialClient, leaderboardCache, leaderboardRankCache, leaderboardScheduler, sessionRegistry, sessionCache, statusRegistry, matchRegistry, tracker, metrics, streamManager, router, runtimeConfig.Path, paths, eventQueue, matchProvider)
	goModules, goRPCFns, goBeforeRtFns, goAfterRtFns, goBeforeReqFns, goAfterReqFns, goMatchmakerMatchedFn, goMatchmakerCustomMatchingFn, goTournamentEndFn, goTournamentResetFn, goLeaderboardResetFn, goPurchaseNotificationAppleFn, goSubscriptionNotificationAppleFn, goPurchaseNotificationGoogleFn, goSubscriptionNotificationGoogleFn, allEventFns, goMatchNamesListFn, err := NewRuntimeProviderGo(ctx, logger, startupLogger, db, protojsonMarshaler, config, version, socialClient, leaderboardCache, leaderboardRankCache, leaderboardScheduler, sessionRegistry, sessionCache, statusRegistry, matchRegistry, tracker, metrics, streamManager, router, runtimeConfig.Path, paths, eventQueue, matchProvider)
	if err != nil {
		startupLogger.Error("Error initialising Go runtime provider", zap.Error(err))
		return nil, nil, err
@@ -2452,6 +2457,14 @@ func NewRuntime(ctx context.Context, logger, startupLogger *zap.Logger, db *sql.
		startupLogger.Info("Registered JavaScript runtime Matchmaker Matched function invocation")
	}

	var allMatchmakerCustomMatchingFunction RuntimeMatchmakerCustomMatchingFunction
	switch {
	case goMatchmakerMatchedFn != nil:
		allMatchmakerCustomMatchingFunction = goMatchmakerCustomMatchingFn
		startupLogger.Info("Registered Go runtime Matchmaker Custom Matching function invocation")
		// TODO: Handle other runtimes.
	}

	var allTournamentEndFunction RuntimeTournamentEndFunction
	switch {
	case goTournamentEndFn != nil:
@@ -2563,6 +2576,7 @@ func NewRuntime(ctx context.Context, logger, startupLogger *zap.Logger, db *sql.
		beforeReqFunctions:                     allBeforeReqFunctions,
		afterReqFunctions:                      allAfterReqFunctions,
		matchmakerMatchedFunction:              allMatchmakerMatchedFunction,
		matchmakerCustomMatchingFunction:       allMatchmakerCustomMatchingFunction,
		tournamentEndFunction:                  allTournamentEndFunction,
		tournamentResetFunction:                allTournamentResetFunction,
		leaderboardResetFunction:               allLeaderboardResetFunction,
+33 −4
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ type RuntimeGoInitializer struct {
	subscriptionNotificationApple  RuntimeSubscriptionNotificationAppleFunction
	purchaseNotificationGoogle     RuntimePurchaseNotificationGoogleFunction
	subscriptionNotificationGoogle RuntimeSubscriptionNotificationGoogleFunction
	matchmakerCustomMatching       RuntimeMatchmakerCustomMatchingFunction

	eventFunctions        []RuntimeEventFunction
	sessionStartFunctions []RuntimeEventFunction
@@ -2481,6 +2482,34 @@ func (ri *RuntimeGoInitializer) RegisterMatchmakerMatched(fn func(ctx context.Co
	return nil
}

func (ri *RuntimeGoInitializer) RegisterRuntimeMatchmakerCustomMatching(fn func(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, matches [][]runtime.MatchmakerEntry) [][]runtime.MatchmakerEntry) error {
	ri.matchmakerCustomMatching = func(ctx context.Context, entries [][]*MatchmakerEntry) [][]*MatchmakerEntry {
		ctx = NewRuntimeGoContext(ctx, ri.node, ri.version, ri.env, RuntimeExecutionModeMatchmakerCustomMatching, nil, nil, 0, "", "", nil, "", "", "", "")
		runtimeCombinations := make([][]runtime.MatchmakerEntry, len(entries))
		for i, combination := range entries {
			runtimeEntry := make([]runtime.MatchmakerEntry, len(combination))
			for j, entry := range combination {
				runtimeEntry[j] = runtime.MatchmakerEntry(entry)
			}
			runtimeCombinations[i] = runtimeEntry
		}

		returnedEntries := fn(ctx, ri.logger.WithField("mode", RuntimeExecutionModeMatchmakerCustomMatching.String()), ri.db, ri.nk, runtimeCombinations)

		combinations := make([][]*MatchmakerEntry, len(entries))
		for i, combination := range returnedEntries {
			entries := make([]*MatchmakerEntry, len(combination))
			for j, entry := range combination {
				e, _ := entry.(*MatchmakerEntry)
				entries[j] = e
			}
			combinations[i] = entries
		}
		return combinations
	}
	return nil
}

func (ri *RuntimeGoInitializer) RegisterTournamentEnd(fn func(ctx context.Context, logger runtime.Logger, db *sql.DB, nk runtime.NakamaModule, tournament *api.Tournament, end, reset int64) error) error {
	ri.tournamentEnd = func(ctx context.Context, tournament *api.Tournament, end, reset int64) error {
		ctx = NewRuntimeGoContext(ctx, ri.node, ri.version, ri.env, RuntimeExecutionModeTournamentEnd, nil, nil, 0, "", "", nil, "", "", "", "")
@@ -2544,7 +2573,7 @@ func (ri *RuntimeGoInitializer) RegisterMatch(name string, fn func(ctx context.C
	return nil
}

func NewRuntimeProviderGo(ctx context.Context, logger, startupLogger *zap.Logger, db *sql.DB, protojsonMarshaler *protojson.MarshalOptions, config Config, version string, socialClient *social.Client, leaderboardCache LeaderboardCache, leaderboardRankCache LeaderboardRankCache, leaderboardScheduler LeaderboardScheduler, sessionRegistry SessionRegistry, sessionCache SessionCache, statusRegistry *StatusRegistry, matchRegistry MatchRegistry, tracker Tracker, metrics Metrics, streamManager StreamManager, router MessageRouter, rootPath string, paths []string, eventQueue *RuntimeEventQueue, matchProvider *MatchProvider) ([]string, map[string]RuntimeRpcFunction, map[string]RuntimeBeforeRtFunction, map[string]RuntimeAfterRtFunction, *RuntimeBeforeReqFunctions, *RuntimeAfterReqFunctions, RuntimeMatchmakerMatchedFunction, RuntimeTournamentEndFunction, RuntimeTournamentResetFunction, RuntimeLeaderboardResetFunction, RuntimePurchaseNotificationAppleFunction, RuntimeSubscriptionNotificationAppleFunction, RuntimePurchaseNotificationGoogleFunction, RuntimeSubscriptionNotificationGoogleFunction, *RuntimeEventFunctions, func() []string, error) {
func NewRuntimeProviderGo(ctx context.Context, logger, startupLogger *zap.Logger, db *sql.DB, protojsonMarshaler *protojson.MarshalOptions, config Config, version string, socialClient *social.Client, leaderboardCache LeaderboardCache, leaderboardRankCache LeaderboardRankCache, leaderboardScheduler LeaderboardScheduler, sessionRegistry SessionRegistry, sessionCache SessionCache, statusRegistry *StatusRegistry, matchRegistry MatchRegistry, tracker Tracker, metrics Metrics, streamManager StreamManager, router MessageRouter, rootPath string, paths []string, eventQueue *RuntimeEventQueue, matchProvider *MatchProvider) ([]string, map[string]RuntimeRpcFunction, map[string]RuntimeBeforeRtFunction, map[string]RuntimeAfterRtFunction, *RuntimeBeforeReqFunctions, *RuntimeAfterReqFunctions, RuntimeMatchmakerMatchedFunction, RuntimeMatchmakerCustomMatchingFunction, RuntimeTournamentEndFunction, RuntimeTournamentResetFunction, RuntimeLeaderboardResetFunction, RuntimePurchaseNotificationAppleFunction, RuntimeSubscriptionNotificationAppleFunction, RuntimePurchaseNotificationGoogleFunction, RuntimeSubscriptionNotificationGoogleFunction, *RuntimeEventFunctions, func() []string, error) {
	runtimeLogger := NewRuntimeGoLogger(logger)
	node := config.GetName()
	env := config.GetRuntime().Environment
@@ -2624,13 +2653,13 @@ func NewRuntimeProviderGo(ctx context.Context, logger, startupLogger *zap.Logger
		relPath, name, fn, err := openGoModule(startupLogger, rootPath, path)
		if err != nil {
			// Errors are already logged in the function above.
			return nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, err
			return nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, err
		}

		// Run the initialisation.
		if err = fn(ctx, runtimeLogger, db, nk, initializer); err != nil {
			startupLogger.Fatal("Error returned by InitModule function in Go module", zap.String("name", name), zap.Error(err))
			return nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, errors.New("error returned by InitModule function in Go module")
			return nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, errors.New("error returned by InitModule function in Go module")
		}
		modulePaths = append(modulePaths, relPath)
	}
@@ -2678,7 +2707,7 @@ func NewRuntimeProviderGo(ctx context.Context, logger, startupLogger *zap.Logger
		}
	}

	return modulePaths, initializer.rpc, initializer.beforeRt, initializer.afterRt, initializer.beforeReq, initializer.afterReq, initializer.matchmakerMatched, initializer.tournamentEnd, initializer.tournamentReset, initializer.leaderboardReset, initializer.purchaseNotificationApple, initializer.subscriptionNotificationApple, initializer.purchaseNotificationGoogle, initializer.subscriptionNotificationGoogle, events, matchNamesListFn, nil
	return modulePaths, initializer.rpc, initializer.beforeRt, initializer.afterRt, initializer.beforeReq, initializer.afterReq, initializer.matchmakerMatched, initializer.matchmakerCustomMatching, initializer.tournamentEnd, initializer.tournamentReset, initializer.leaderboardReset, initializer.purchaseNotificationApple, initializer.subscriptionNotificationApple, initializer.purchaseNotificationGoogle, initializer.subscriptionNotificationGoogle, events, matchNamesListFn, nil
}

func CheckRuntimeProviderGo(logger *zap.Logger, rootPath string, paths []string) error {
+3 −0
Original line number Diff line number Diff line
@@ -336,6 +336,9 @@ type Initializer interface {
	// RegisterMatchmakerMatched
	RegisterMatchmakerMatched(fn func(ctx context.Context, logger Logger, db *sql.DB, nk NakamaModule, entries []MatchmakerEntry) (string, error)) error

	// RegisterRuntimeMatchmakerCustomMatching
	RegisterRuntimeMatchmakerCustomMatching(fn func(ctx context.Context, logger Logger, db *sql.DB, nk NakamaModule, entries [][]MatchmakerEntry) (matches [][]MatchmakerEntry)) error

	// RegisterMatch
	RegisterMatch(name string, fn func(ctx context.Context, logger Logger, db *sql.DB, nk NakamaModule) (Match, error)) error