diff --git a/server/matchmaker.go b/server/matchmaker.go index 26a6ad0497832f178ffae5877185d103732d5899..220855c728a6d4cd6db28c3fc3e4dcf92d2d596a 100644 --- a/server/matchmaker.go +++ b/server/matchmaker.go @@ -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() } diff --git a/server/matchmaker_process.go b/server/matchmaker_process.go index 5d79a33a0fafc93cf86aa656fa772d654b44ca58..2786224fbf13b5799c37105a6a793bbc916981d6 100644 --- a/server/matchmaker_process.go +++ b/server/matchmaker_process.go @@ -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)) diff --git a/server/runtime.go b/server/runtime.go index a755493910f0222d891360fad369237887c24e7c..cc3fbedac207eaa25e6708cd404b52691e29b34c 100644 --- a/server/runtime.go +++ b/server/runtime.go @@ -208,7 +208,8 @@ type ( RuntimeBeforeGetSubscriptionFunction func(ctx context.Context, logger *zap.Logger, userID, username string, vars map[string]string, expiry int64, clientIP, clientPort string, in *api.GetSubscriptionRequest) (*api.GetSubscriptionRequest, error, codes.Code) 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) + 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: @@ -497,7 +501,8 @@ type Runtime struct { beforeReqFunctions *RuntimeBeforeReqFunctions afterReqFunctions *RuntimeAfterReqFunctions - matchmakerMatchedFunction RuntimeMatchmakerMatchedFunction + 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, diff --git a/server/runtime_go.go b/server/runtime_go.go index 6a111f7403c43edbf4f0f3611194d396534feda2..552d0cd20e48b14bbc4df328f0fbf7ad4575cae2 100644 --- a/server/runtime_go.go +++ b/server/runtime_go.go @@ -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 { diff --git a/vendor/github.com/heroiclabs/nakama-common/runtime/runtime.go b/vendor/github.com/heroiclabs/nakama-common/runtime/runtime.go index ec3e906e5f290e3cf725a282d5253e2a5987c4e3..266baf715d9e78ba5492c66914b6c164e2afbc57 100644 --- a/vendor/github.com/heroiclabs/nakama-common/runtime/runtime.go +++ b/vendor/github.com/heroiclabs/nakama-common/runtime/runtime.go @@ -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