From 37d0702d5cc4d492bfce86e79d990200ceb0b489 Mon Sep 17 00:00:00 2001 From: Steve Date: Sun, 25 Jul 2021 17:22:57 -0400 Subject: [PATCH] allow server to handle multiple matches --- cmd/client/main.go | 6 +++ internal/coordinator/coordinator.go | 82 ++++++++++++++++++----------- internal/coordinator/session.go | 27 +++++++--- 3 files changed, 77 insertions(+), 38 deletions(-) diff --git a/cmd/client/main.go b/cmd/client/main.go index 4375c88..5999f73 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -21,6 +21,7 @@ import ( var done chan interface{} var interrupt chan os.Signal var pid int +var matchID uuid.UUID func receiveHandler(connection *websocket.Conn, output chan string) { defer close(done) @@ -37,6 +38,7 @@ func receiveHandler(connection *websocket.Conn, output chan string) { pid = game.ScourgeID output <- "joined as scourge" } else if resp.Result == coordinator.SessionRespFound { + matchID = resp.MatchID output <- "game found" } else if resp.Result == coordinator.SessionRespPlayed { if resp.GameResult != nil { @@ -149,11 +151,13 @@ func GetCommand(uid uuid.UUID, resp chan coordinator.SessionCommand) { case coordinator.SessionCmdJoin: resp <- coordinator.SessionCommand{ ID: uid, + MatchID: matchID, Command: coordinator.SessionCmdJoin, } case coordinator.SessionCmdLeave: resp <- coordinator.SessionCommand{ ID: uid, + MatchID: matchID, Command: coordinator.SessionCmdLeave, } default: @@ -163,6 +167,7 @@ func GetCommand(uid uuid.UUID, resp chan coordinator.SessionCommand) { //state resp <- coordinator.SessionCommand{ ID: uid, + MatchID: matchID, Command: coordinator.SessionCmdPlay, GameCommand: &game.Command{ PlayerID: pid, @@ -174,6 +179,7 @@ func GetCommand(uid uuid.UUID, resp chan coordinator.SessionCommand) { //action resp <- coordinator.SessionCommand{ ID: uid, + MatchID: matchID, Command: coordinator.SessionCmdPlay, GameCommand: &game.Command{ PlayerID: pid, diff --git a/internal/coordinator/coordinator.go b/internal/coordinator/coordinator.go index 953ee98..bf4bae3 100644 --- a/internal/coordinator/coordinator.go +++ b/internal/coordinator/coordinator.go @@ -10,16 +10,16 @@ import ( ) type Coordinator struct { - Match *Session + Matches map[uuid.UUID]*Session PlayerQueueChan chan uuid.UUID - CallbackChan map[uuid.UUID]chan bool + CallbackChan map[uuid.UUID]chan uuid.UUID } func NewCoordinator() *Coordinator { return &Coordinator{ - Match: NewSession(), + Matches: make(map[uuid.UUID]*Session), PlayerQueueChan: make(chan uuid.UUID), - CallbackChan: make(map[uuid.UUID]chan bool), + CallbackChan: make(map[uuid.UUID]chan uuid.UUID), } } @@ -31,16 +31,21 @@ func (c *Coordinator) Start() { fmt.Println("p1 join") p2 = <-c.PlayerQueueChan fmt.Println("p2 join") - c.Match = m + m.Active = true m.Game = game.NewGame() - c.CallbackChan[p1] <- true - c.CallbackChan[p2] <- true + c.Matches[m.ID] = m + c.CallbackChan[p1] <- m.ID + c.CallbackChan[p2] <- m.ID }() go func() { - time.Sleep(5) - if c.Match.Game == nil { - log.Println("clearing old match") - c.Match = nil + for { + time.Sleep(10) + for _, v := range c.Matches { + if v.Game == nil && v.Active { + log.Println("clearing match with no game") + delete(c.Matches, v.ID) + } + } } }() @@ -49,47 +54,64 @@ func (c *Coordinator) Start() { func (c *Coordinator) Coordinate(cmd *SessionCommand) *SessionCommandResult { switch cmd.Command { case SessionCmdQuery: - c.CallbackChan[cmd.ID] = make(chan bool) + c.CallbackChan[cmd.ID] = make(chan uuid.UUID) c.PlayerQueueChan <- cmd.ID - <-c.CallbackChan[cmd.ID] + m := <-c.CallbackChan[cmd.ID] return &SessionCommandResult{ - ID: cmd.ID, - Result: SessionRespFound, + ID: cmd.ID, + MatchID: m, + Result: SessionRespFound, } case SessionCmdJoin: - if c.Match == nil { + m, exists := c.Matches[cmd.MatchID] + if !exists { return &SessionCommandResult{ - ID: cmd.ID, - Result: SessionRespJoinError, + ID: cmd.ID, + MatchID: uuid.Nil, + Result: SessionRespJoinError, } } - resp := c.Match.Join(cmd.ID) + resp := m.Join(cmd.ID) return &SessionCommandResult{ - ID: cmd.ID, - Result: resp, + ID: cmd.ID, + MatchID: m.ID, + Result: resp, } case SessionCmdLeave: - if c.Match == nil { + m, exists := c.Matches[cmd.MatchID] + if !exists || !m.PlayerIn(cmd.ID) { return &SessionCommandResult{ - ID: cmd.ID, - Result: SessionRespLeft, + ID: cmd.ID, + MatchID: uuid.Nil, + Result: SessionRespLeft, } } - c.Match.Leave(cmd.ID) + m.Leave(cmd.ID) return &SessionCommandResult{ - ID: cmd.ID, - Result: SessionRespLeft, + ID: cmd.ID, + MatchID: uuid.Nil, + Result: SessionRespLeft, } case SessionCmdPlay: - resp := c.Match.Play(cmd.ID, cmd.GameCommand) + m, exists := c.Matches[cmd.MatchID] + if !exists || !m.PlayerIn(cmd.ID) { + return &SessionCommandResult{ + ID: cmd.ID, + MatchID: uuid.Nil, + Result: SessionRespLeft, + } + } + resp := m.Play(cmd.ID, cmd.GameCommand) return &SessionCommandResult{ ID: cmd.ID, + MatchID: m.ID, Result: SessionRespPlayed, GameResult: resp, } } return &SessionCommandResult{ - ID: cmd.ID, - Result: SessionRespError, + ID: cmd.ID, + MatchID: uuid.Nil, + Result: SessionRespError, } } diff --git a/internal/coordinator/session.go b/internal/coordinator/session.go index 26fbaa0..56abc30 100644 --- a/internal/coordinator/session.go +++ b/internal/coordinator/session.go @@ -28,18 +28,22 @@ const ( ) type Session struct { - p1 uuid.UUID - p2 uuid.UUID - pMap map[uuid.UUID]int - Game *game.Game + ID uuid.UUID + p1 uuid.UUID + p2 uuid.UUID + pMap map[uuid.UUID]int + Active bool + Game *game.Game } func NewSession() *Session { return &Session{ - p1: uuid.Nil, - p2: uuid.Nil, - pMap: make(map[uuid.UUID]int), - Game: nil, + ID: uuid.New(), + p1: uuid.Nil, + p2: uuid.Nil, + pMap: make(map[uuid.UUID]int), + Active: false, + Game: nil, } } @@ -78,8 +82,14 @@ func (s *Session) Play(id uuid.UUID, cmd *game.Command) *game.CommandResult { return res } +func (s *Session) PlayerIn(id uuid.UUID) bool { + _, exists := s.pMap[id] + return exists +} + type SessionCommand struct { ID uuid.UUID `json:"player_id"` + MatchID uuid.UUID `json:"match_id"` Command SessionCmd `json:"command"` GameCommand *game.Command `json:"game_command,omitempty"` } @@ -90,6 +100,7 @@ func (s *SessionCommand) String() string { type SessionCommandResult struct { ID uuid.UUID `json:"player_id"` + MatchID uuid.UUID `json:"match_id"` Result SessionResp `json:"result"` GameResult *game.CommandResult `json:"game_result,omitempty"` }