From 9b3e98c0f418f8f800028c95196c686bcebd3664 Mon Sep 17 00:00:00 2001 From: Zak <34372536+ZakShearman@users.noreply.github.com> Date: Mon, 9 Sep 2024 22:15:50 +0100 Subject: [PATCH] feat: edge support --- go.mod | 2 +- go.sum | 4 ++ internal/app/kurushimi.go | 15 ++++++-- internal/config/global.go | 26 +++++++++++++ internal/service/matchmaker.go | 21 ++++++---- internal/service/public.go | 8 ++-- .../simple_controller.go} | 38 ++++++++++--------- 7 files changed, 81 insertions(+), 33 deletions(-) rename internal/{lobbycontroller/lobby.go => simplecontroller/simple_controller.go} (76%) diff --git a/go.mod b/go.mod index 797ea18..7a99748 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.23 require ( agones.dev/agones v1.42.0 github.com/emortalmc/live-config-parser/golang v0.0.0-20231228020729-d2b6294e5968 - github.com/emortalmc/proto-specs/gen/go v0.0.0-20231227235524-ca990cc793bf + github.com/emortalmc/proto-specs/gen/go v0.0.0-20240909151321-29fd34625282 github.com/google/uuid v1.5.0 github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1 github.com/segmentio/kafka-go v0.4.47 diff --git a/go.sum b/go.sum index 3f53cc8..9fe4879 100644 --- a/go.sum +++ b/go.sum @@ -13,6 +13,10 @@ github.com/emortalmc/live-config-parser/golang v0.0.0-20231228020729-d2b6294e596 github.com/emortalmc/live-config-parser/golang v0.0.0-20231228020729-d2b6294e5968/go.mod h1:CbOcbHzizWqxyflDiBKyU9LIVxZw6t5V2NlWLVfgkwY= github.com/emortalmc/proto-specs/gen/go v0.0.0-20231227235524-ca990cc793bf h1:hAMusd3Zu4w9wJBMsNfPitbeu939vSYj1Q1x9ZrbO7U= github.com/emortalmc/proto-specs/gen/go v0.0.0-20231227235524-ca990cc793bf/go.mod h1:se+tHcK9FWxeadkxLF5uj+SPauEye0X+Iq6cGczXGJY= +github.com/emortalmc/proto-specs/gen/go v0.0.0-20240909151212-bfb0f4305228 h1:oQxnDDw5FFkDm8qdWLRbibaijSKpIsjRuFtsg7sFcNk= +github.com/emortalmc/proto-specs/gen/go v0.0.0-20240909151212-bfb0f4305228/go.mod h1:se+tHcK9FWxeadkxLF5uj+SPauEye0X+Iq6cGczXGJY= +github.com/emortalmc/proto-specs/gen/go v0.0.0-20240909151321-29fd34625282 h1:tqF4UWZeUoC0h+nvb+mqakexuSrhEK6LGmQRep+84I0= +github.com/emortalmc/proto-specs/gen/go v0.0.0-20240909151321-29fd34625282/go.mod h1:se+tHcK9FWxeadkxLF5uj+SPauEye0X+Iq6cGczXGJY= github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84= github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= diff --git a/internal/app/kurushimi.go b/internal/app/kurushimi.go index 4c64a8c..c14e688 100644 --- a/internal/app/kurushimi.go +++ b/internal/app/kurushimi.go @@ -6,9 +6,9 @@ import ( "github.com/emortalmc/kurushimi/internal/config" "github.com/emortalmc/kurushimi/internal/director" "github.com/emortalmc/kurushimi/internal/kafka" - "github.com/emortalmc/kurushimi/internal/lobbycontroller" "github.com/emortalmc/kurushimi/internal/repository" "github.com/emortalmc/kurushimi/internal/service" + "github.com/emortalmc/kurushimi/internal/simplecontroller" "github.com/emortalmc/kurushimi/internal/utils/kubernetes" "github.com/emortalmc/live-config-parser/golang/pkg/liveconfig" "github.com/emortalmc/proto-specs/gen/go/grpc/party" @@ -74,10 +74,17 @@ func Run(cfg config.Config, logger *zap.SugaredLogger) { partyService := party.NewPartyServiceClient(pConn) - // Lobby controller - lobbyCtrl := lobbycontroller.NewLobbyController(ctx, wg, logger, cfg.Lobby, notifier, allocationClient) + // Simple controllers + lobbyCfg := cfg.Lobby + proxyCfg := cfg.Proxy - service.RunServices(ctx, logger, wg, cfg, repo, notifier, gameModeController, lobbyCtrl, partyService, partySettingsService) + lobbyCtrl := simplecontroller.NewJoinController(ctx, wg, logger, notifier, allocationClient, + lobbyCfg.FleetName, "lobby", lobbyCfg.MatchRate, lobbyCfg.MatchSize) + + velocityCtrl := simplecontroller.NewJoinController(ctx, wg, logger, notifier, allocationClient, + proxyCfg.FleetName, "proxy", proxyCfg.MatchRate, proxyCfg.MatchSize) + + service.RunServices(ctx, logger, wg, cfg, repo, notifier, gameModeController, lobbyCtrl, velocityCtrl, partyService, partySettingsService) directR := director.New(logger, repo, notifier, allocationClient, gameModeController) directR.Start(ctx) diff --git a/internal/config/global.go b/internal/config/global.go index f77340d..bb215e0 100644 --- a/internal/config/global.go +++ b/internal/config/global.go @@ -24,6 +24,10 @@ const ( lobbyMatchRateFlag = "lobby-match-rate" lobbyMatchSizeFlag = "lobby-match-size" + proxyFleetNameFlag = "proxy-fleet-name" + proxyMatchRateFlag = "proxy-match-rate" + proxyMatchSizeFlag = "proxy-match-size" + grpcPortFlag = "port" developmentFlag = "development" ) @@ -35,6 +39,7 @@ type Config struct { PartyService PartyServiceConfig Lobby LobbyConfig + Proxy ProxyConfig Namespace string GrpcPort int @@ -64,6 +69,12 @@ type LobbyConfig struct { MatchSize int } +type ProxyConfig struct { + FleetName string + MatchRate time.Duration + MatchSize int +} + func LoadGlobalConfig() Config { // Kafka viper.SetDefault(kafkaHostFlag, "localhost") @@ -79,6 +90,10 @@ func LoadGlobalConfig() Config { viper.SetDefault(lobbyFleetNameFlag, "lobby") viper.SetDefault(lobbyMatchRateFlag, 175_000_000) viper.SetDefault(lobbyMatchSizeFlag, 50) + // Proxy + viper.SetDefault(proxyFleetNameFlag, "velocity") + viper.SetDefault(proxyMatchRateFlag, 175_000_000) + viper.SetDefault(proxyMatchSizeFlag, 50) // Global viper.SetDefault(namespaceFlag, "emortalmc") viper.SetDefault(grpcPortFlag, 1007) @@ -94,6 +109,9 @@ func LoadGlobalConfig() Config { pflag.String(lobbyFleetNameFlag, viper.GetString(lobbyFleetNameFlag), "Lobby fleet name") pflag.Duration(lobbyMatchRateFlag, viper.GetDuration(lobbyMatchRateFlag), "Delay between creating lobby matches") pflag.Int32(lobbyMatchSizeFlag, viper.GetInt32(lobbyMatchSizeFlag), "Maximum size of a lobby (accounts for players already in the lobby)") + pflag.String(proxyFleetNameFlag, viper.GetString(proxyFleetNameFlag), "Proxy fleet name (default velocity)") + pflag.Duration(proxyMatchRateFlag, viper.GetDuration(proxyMatchRateFlag), "Delay between creating proxy matches") + pflag.Int32(proxyMatchSizeFlag, viper.GetInt32(proxyMatchSizeFlag), "Maximum size of a proxy (accounts for players already in the proxy)") pflag.String(namespaceFlag, viper.GetString(namespaceFlag), "Namespace that the resource is in") pflag.Int32(grpcPortFlag, viper.GetInt32(grpcPortFlag), "gRPC port of THIS service") pflag.Bool(developmentFlag, viper.GetBool(developmentFlag), "Development mode") @@ -111,6 +129,9 @@ func LoadGlobalConfig() Config { runtime.Must(viper.BindEnv(lobbyFleetNameFlag)) runtime.Must(viper.BindEnv(lobbyMatchRateFlag)) runtime.Must(viper.BindEnv(lobbyMatchSizeFlag)) + runtime.Must(viper.BindEnv(proxyFleetNameFlag)) + runtime.Must(viper.BindEnv(proxyMatchRateFlag)) + runtime.Must(viper.BindEnv(proxyMatchSizeFlag)) runtime.Must(viper.BindEnv(namespaceFlag)) runtime.Must(viper.BindEnv(grpcPortFlag)) runtime.Must(viper.BindEnv(developmentFlag)) @@ -134,6 +155,11 @@ func LoadGlobalConfig() Config { MatchRate: viper.GetDuration(lobbyMatchRateFlag), MatchSize: int(viper.GetInt32(lobbyMatchSizeFlag)), }, + Proxy: ProxyConfig{ + FleetName: viper.GetString(proxyFleetNameFlag), + MatchRate: viper.GetDuration(proxyMatchRateFlag), + MatchSize: int(viper.GetInt32(proxyMatchSizeFlag)), + }, Namespace: viper.GetString(namespaceFlag), GrpcPort: int(viper.GetInt32(grpcPortFlag)), Development: viper.GetBool(developmentFlag), diff --git a/internal/service/matchmaker.go b/internal/service/matchmaker.go index 4f8b83f..1d26f09 100644 --- a/internal/service/matchmaker.go +++ b/internal/service/matchmaker.go @@ -4,9 +4,9 @@ import ( "context" "fmt" "github.com/emortalmc/kurushimi/internal/kafka" - "github.com/emortalmc/kurushimi/internal/lobbycontroller" "github.com/emortalmc/kurushimi/internal/repository" "github.com/emortalmc/kurushimi/internal/repository/model" + "github.com/emortalmc/kurushimi/internal/simplecontroller" "github.com/emortalmc/live-config-parser/golang/pkg/liveconfig" "github.com/emortalmc/proto-specs/gen/go/grpc/matchmaker" pbparty "github.com/emortalmc/proto-specs/gen/go/grpc/party" @@ -29,14 +29,16 @@ type matchmakerService struct { notifier kafka.Notifier cfgController liveconfig.GameModeConfigController - lobbyController lobbycontroller.LobbyController + lobbyController simplecontroller.SimpleController + velocityController simplecontroller.SimpleController partyService pbparty.PartyServiceClient partySettingsService pbparty.PartySettingsServiceClient } func newMatchmakerService(logger *zap.SugaredLogger, repository repository.Repository, notifier kafka.Notifier, - cfgController liveconfig.GameModeConfigController, lobbyController lobbycontroller.LobbyController, + cfgController liveconfig.GameModeConfigController, lobbyController simplecontroller.SimpleController, + velocityController simplecontroller.SimpleController, partyService pbparty.PartyServiceClient, partySettingsService pbparty.PartySettingsServiceClient) matchmaker.MatchmakerServer { return &matchmakerService{ @@ -45,7 +47,8 @@ func newMatchmakerService(logger *zap.SugaredLogger, repository repository.Repos notifier: notifier, cfgController: cfgController, - lobbyController: lobbyController, + lobbyController: lobbyController, + velocityController: velocityController, partyService: partyService, partySettingsService: partySettingsService, @@ -284,15 +287,19 @@ func (m *matchmakerService) SendPlayersToLobby(ctx context.Context, request *mat return &matchmaker.SendPlayerToLobbyResponse{}, nil } -func (m *matchmakerService) QueueInitialLobbyByPlayer(_ context.Context, request *matchmaker.QueueInitialLobbyByPlayerRequest) (*matchmaker.QueueInitialLobbyByPlayerResponse, error) { +func (m *matchmakerService) LoginQueueByPlayer(_ context.Context, request *matchmaker.LoginQueueByPlayerRequest) (*matchmaker.LoginQueueByPlayerResponse, error) { playerId, err := uuid.Parse(request.PlayerId) if err != nil { return nil, status.Error(codes.InvalidArgument, "invalid player_id") } - m.lobbyController.QueuePlayer(playerId, false) + if !request.IsProxy { + m.lobbyController.QueuePlayer(playerId, false) + } else { + m.velocityController.QueuePlayer(playerId, false) + } - return &matchmaker.QueueInitialLobbyByPlayerResponse{}, nil + return &matchmaker.LoginQueueByPlayerResponse{}, nil } var ( diff --git a/internal/service/public.go b/internal/service/public.go index 1bed52d..37d0ff6 100644 --- a/internal/service/public.go +++ b/internal/service/public.go @@ -5,8 +5,8 @@ import ( "fmt" "github.com/emortalmc/kurushimi/internal/config" "github.com/emortalmc/kurushimi/internal/kafka" - "github.com/emortalmc/kurushimi/internal/lobbycontroller" "github.com/emortalmc/kurushimi/internal/repository" + "github.com/emortalmc/kurushimi/internal/simplecontroller" "github.com/emortalmc/kurushimi/internal/utils/grpczap" "github.com/emortalmc/live-config-parser/golang/pkg/liveconfig" "github.com/emortalmc/proto-specs/gen/go/grpc/matchmaker" @@ -21,8 +21,8 @@ import ( func RunServices(ctx context.Context, logger *zap.SugaredLogger, wg *sync.WaitGroup, cfg config.Config, repo repository.Repository, notifier kafka.Notifier, gameModeController liveconfig.GameModeConfigController, - lobbyCtrl lobbycontroller.LobbyController, partyService party.PartyServiceClient, - partySettingsService party.PartySettingsServiceClient) { + lobbyCtrl simplecontroller.SimpleController, velocityCtrl simplecontroller.SimpleController, + partyService party.PartyServiceClient, partySettingsService party.PartySettingsServiceClient) { lis, err := net.Listen("tcp", fmt.Sprintf(":%d", cfg.GrpcPort)) if err != nil { @@ -43,7 +43,7 @@ func RunServices(ctx context.Context, logger *zap.SugaredLogger, wg *sync.WaitGr } matchmaker.RegisterMatchmakerServer(s, newMatchmakerService(logger, repo, notifier, gameModeController, lobbyCtrl, - partyService, partySettingsService)) + velocityCtrl, partyService, partySettingsService)) logger.Infow("listening for gRPC requests", "port", cfg.GrpcPort) go func() { diff --git a/internal/lobbycontroller/lobby.go b/internal/simplecontroller/simple_controller.go similarity index 76% rename from internal/lobbycontroller/lobby.go rename to internal/simplecontroller/simple_controller.go index bbfbc3e..bbb26a6 100644 --- a/internal/lobbycontroller/lobby.go +++ b/internal/simplecontroller/simple_controller.go @@ -1,10 +1,9 @@ -package lobbycontroller +package simplecontroller import ( v13 "agones.dev/agones/pkg/apis/allocation/v1" v1 "agones.dev/agones/pkg/client/clientset/versioned/typed/allocation/v1" "context" - "github.com/emortalmc/kurushimi/internal/config" "github.com/emortalmc/kurushimi/internal/gsallocation" "github.com/emortalmc/kurushimi/internal/gsallocation/selector" "github.com/emortalmc/kurushimi/internal/kafka" @@ -17,12 +16,15 @@ import ( "time" ) -type LobbyController interface { +// SimpleController is a controller to allocate players into matches for simple servers - not gamemodes. +// It is necessary due to Agones behaviours we want to work around for lobbies and proxies. +type SimpleController interface { QueuePlayer(playerId uuid.UUID, autoTeleport bool) } -type lobbyControllerImpl struct { +type simpleControllerImpl struct { fleetName string + gameModeId string matchmakingRate time.Duration playersPerMatch int @@ -35,13 +37,15 @@ type lobbyControllerImpl struct { queuedPlayersLock sync.Mutex } -func NewLobbyController(ctx context.Context, wg *sync.WaitGroup, logger *zap.SugaredLogger, cfg config.LobbyConfig, notifier kafka.Notifier, - allocatorClient v1.GameServerAllocationInterface) LobbyController { +func NewJoinController(ctx context.Context, wg *sync.WaitGroup, logger *zap.SugaredLogger, notifier kafka.Notifier, + allocatorClient v1.GameServerAllocationInterface, fleetName string, gameModeID string, matchRate time.Duration, + playersPerMatch int) SimpleController { - c := &lobbyControllerImpl{ - fleetName: cfg.FleetName, - matchmakingRate: cfg.MatchRate, - playersPerMatch: cfg.MatchSize, + c := &simpleControllerImpl{ + fleetName: fleetName, + gameModeId: gameModeID, + matchmakingRate: matchRate, + playersPerMatch: playersPerMatch, logger: logger, notifier: notifier, @@ -56,14 +60,14 @@ func NewLobbyController(ctx context.Context, wg *sync.WaitGroup, logger *zap.Sug return c } -func (l *lobbyControllerImpl) QueuePlayer(playerId uuid.UUID, autoTeleport bool) { +func (l *simpleControllerImpl) QueuePlayer(playerId uuid.UUID, autoTeleport bool) { l.queuedPlayersLock.Lock() defer l.queuedPlayersLock.Unlock() l.queuedPlayers[playerId] = autoTeleport } -func (l *lobbyControllerImpl) run(wg *sync.WaitGroup, ctx context.Context) { +func (l *simpleControllerImpl) run(wg *sync.WaitGroup, ctx context.Context) { go func() { for { if ctx.Err() != nil { @@ -100,7 +104,7 @@ func (l *lobbyControllerImpl) run(wg *sync.WaitGroup, ctx context.Context) { }() } -func (l *lobbyControllerImpl) resetQueuedPlayers() map[uuid.UUID]bool { +func (l *simpleControllerImpl) resetQueuedPlayers() map[uuid.UUID]bool { l.queuedPlayersLock.Lock() defer l.queuedPlayersLock.Unlock() @@ -114,7 +118,7 @@ func (l *lobbyControllerImpl) resetQueuedPlayers() map[uuid.UUID]bool { return queuedPlayers } -func (l *lobbyControllerImpl) createMatchesFromPlayers(playerMap map[uuid.UUID]bool) map[*pb.Match]*v13.GameServerAllocation { +func (l *simpleControllerImpl) createMatchesFromPlayers(playerMap map[uuid.UUID]bool) map[*pb.Match]*v13.GameServerAllocation { allocationReqs := make(map[*pb.Match]*v13.GameServerAllocation) if len(playerMap) > 0 { @@ -123,7 +127,7 @@ func (l *lobbyControllerImpl) createMatchesFromPlayers(playerMap map[uuid.UUID]b currentMatch := &pb.Match{ Id: primitive.NewObjectID().String(), - GameModeId: "lobby", + GameModeId: l.gameModeId, MapId: nil, Tickets: make([]*pb.Ticket, 0), Assignment: nil, @@ -134,7 +138,7 @@ func (l *lobbyControllerImpl) createMatchesFromPlayers(playerMap map[uuid.UUID]b currentMatch.Tickets = append(currentMatch.Tickets, &pb.Ticket{ PlayerIds: []string{playerId.String()}, CreatedAt: timestamppb.Now(), - GameModeId: "lobby", + GameModeId: l.gameModeId, AutoTeleport: autoTeleport, DequeueOnDisconnect: false, InPendingMatch: false, @@ -145,7 +149,7 @@ func (l *lobbyControllerImpl) createMatchesFromPlayers(playerMap map[uuid.UUID]b allocationReqs[currentMatch] = selector.CreatePlayerBasedSelector(l.fleetName, currentMatch, int64(currentCount)) currentMatch = &pb.Match{ Id: primitive.NewObjectID().Hex(), - GameModeId: "lobby", + GameModeId: l.gameModeId, MapId: nil, Tickets: make([]*pb.Ticket, 0), Assignment: nil,