allow server to handle multiple matches

This commit is contained in:
stryan 2021-07-25 17:22:57 -04:00
parent 907cf269cd
commit 37d0702d5c
3 changed files with 77 additions and 38 deletions

View File

@ -21,6 +21,7 @@ import (
var done chan interface{} var done chan interface{}
var interrupt chan os.Signal var interrupt chan os.Signal
var pid int var pid int
var matchID uuid.UUID
func receiveHandler(connection *websocket.Conn, output chan string) { func receiveHandler(connection *websocket.Conn, output chan string) {
defer close(done) defer close(done)
@ -37,6 +38,7 @@ func receiveHandler(connection *websocket.Conn, output chan string) {
pid = game.ScourgeID pid = game.ScourgeID
output <- "joined as scourge" output <- "joined as scourge"
} else if resp.Result == coordinator.SessionRespFound { } else if resp.Result == coordinator.SessionRespFound {
matchID = resp.MatchID
output <- "game found" output <- "game found"
} else if resp.Result == coordinator.SessionRespPlayed { } else if resp.Result == coordinator.SessionRespPlayed {
if resp.GameResult != nil { if resp.GameResult != nil {
@ -149,11 +151,13 @@ func GetCommand(uid uuid.UUID, resp chan coordinator.SessionCommand) {
case coordinator.SessionCmdJoin: case coordinator.SessionCmdJoin:
resp <- coordinator.SessionCommand{ resp <- coordinator.SessionCommand{
ID: uid, ID: uid,
MatchID: matchID,
Command: coordinator.SessionCmdJoin, Command: coordinator.SessionCmdJoin,
} }
case coordinator.SessionCmdLeave: case coordinator.SessionCmdLeave:
resp <- coordinator.SessionCommand{ resp <- coordinator.SessionCommand{
ID: uid, ID: uid,
MatchID: matchID,
Command: coordinator.SessionCmdLeave, Command: coordinator.SessionCmdLeave,
} }
default: default:
@ -163,6 +167,7 @@ func GetCommand(uid uuid.UUID, resp chan coordinator.SessionCommand) {
//state //state
resp <- coordinator.SessionCommand{ resp <- coordinator.SessionCommand{
ID: uid, ID: uid,
MatchID: matchID,
Command: coordinator.SessionCmdPlay, Command: coordinator.SessionCmdPlay,
GameCommand: &game.Command{ GameCommand: &game.Command{
PlayerID: pid, PlayerID: pid,
@ -174,6 +179,7 @@ func GetCommand(uid uuid.UUID, resp chan coordinator.SessionCommand) {
//action //action
resp <- coordinator.SessionCommand{ resp <- coordinator.SessionCommand{
ID: uid, ID: uid,
MatchID: matchID,
Command: coordinator.SessionCmdPlay, Command: coordinator.SessionCmdPlay,
GameCommand: &game.Command{ GameCommand: &game.Command{
PlayerID: pid, PlayerID: pid,

View File

@ -10,16 +10,16 @@ import (
) )
type Coordinator struct { type Coordinator struct {
Match *Session Matches map[uuid.UUID]*Session
PlayerQueueChan chan uuid.UUID PlayerQueueChan chan uuid.UUID
CallbackChan map[uuid.UUID]chan bool CallbackChan map[uuid.UUID]chan uuid.UUID
} }
func NewCoordinator() *Coordinator { func NewCoordinator() *Coordinator {
return &Coordinator{ return &Coordinator{
Match: NewSession(), Matches: make(map[uuid.UUID]*Session),
PlayerQueueChan: make(chan uuid.UUID), 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") fmt.Println("p1 join")
p2 = <-c.PlayerQueueChan p2 = <-c.PlayerQueueChan
fmt.Println("p2 join") fmt.Println("p2 join")
c.Match = m m.Active = true
m.Game = game.NewGame() m.Game = game.NewGame()
c.CallbackChan[p1] <- true c.Matches[m.ID] = m
c.CallbackChan[p2] <- true c.CallbackChan[p1] <- m.ID
c.CallbackChan[p2] <- m.ID
}() }()
go func() { go func() {
time.Sleep(5) for {
if c.Match.Game == nil { time.Sleep(10)
log.Println("clearing old match") for _, v := range c.Matches {
c.Match = nil 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 { func (c *Coordinator) Coordinate(cmd *SessionCommand) *SessionCommandResult {
switch cmd.Command { switch cmd.Command {
case SessionCmdQuery: case SessionCmdQuery:
c.CallbackChan[cmd.ID] = make(chan bool) c.CallbackChan[cmd.ID] = make(chan uuid.UUID)
c.PlayerQueueChan <- cmd.ID c.PlayerQueueChan <- cmd.ID
<-c.CallbackChan[cmd.ID] m := <-c.CallbackChan[cmd.ID]
return &SessionCommandResult{ return &SessionCommandResult{
ID: cmd.ID, ID: cmd.ID,
Result: SessionRespFound, MatchID: m,
Result: SessionRespFound,
} }
case SessionCmdJoin: case SessionCmdJoin:
if c.Match == nil { m, exists := c.Matches[cmd.MatchID]
if !exists {
return &SessionCommandResult{ return &SessionCommandResult{
ID: cmd.ID, ID: cmd.ID,
Result: SessionRespJoinError, MatchID: uuid.Nil,
Result: SessionRespJoinError,
} }
} }
resp := c.Match.Join(cmd.ID) resp := m.Join(cmd.ID)
return &SessionCommandResult{ return &SessionCommandResult{
ID: cmd.ID, ID: cmd.ID,
Result: resp, MatchID: m.ID,
Result: resp,
} }
case SessionCmdLeave: case SessionCmdLeave:
if c.Match == nil { m, exists := c.Matches[cmd.MatchID]
if !exists || !m.PlayerIn(cmd.ID) {
return &SessionCommandResult{ return &SessionCommandResult{
ID: cmd.ID, ID: cmd.ID,
Result: SessionRespLeft, MatchID: uuid.Nil,
Result: SessionRespLeft,
} }
} }
c.Match.Leave(cmd.ID) m.Leave(cmd.ID)
return &SessionCommandResult{ return &SessionCommandResult{
ID: cmd.ID, ID: cmd.ID,
Result: SessionRespLeft, MatchID: uuid.Nil,
Result: SessionRespLeft,
} }
case SessionCmdPlay: 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{ return &SessionCommandResult{
ID: cmd.ID, ID: cmd.ID,
MatchID: m.ID,
Result: SessionRespPlayed, Result: SessionRespPlayed,
GameResult: resp, GameResult: resp,
} }
} }
return &SessionCommandResult{ return &SessionCommandResult{
ID: cmd.ID, ID: cmd.ID,
Result: SessionRespError, MatchID: uuid.Nil,
Result: SessionRespError,
} }
} }

View File

@ -28,18 +28,22 @@ const (
) )
type Session struct { type Session struct {
p1 uuid.UUID ID uuid.UUID
p2 uuid.UUID p1 uuid.UUID
pMap map[uuid.UUID]int p2 uuid.UUID
Game *game.Game pMap map[uuid.UUID]int
Active bool
Game *game.Game
} }
func NewSession() *Session { func NewSession() *Session {
return &Session{ return &Session{
p1: uuid.Nil, ID: uuid.New(),
p2: uuid.Nil, p1: uuid.Nil,
pMap: make(map[uuid.UUID]int), p2: uuid.Nil,
Game: 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 return res
} }
func (s *Session) PlayerIn(id uuid.UUID) bool {
_, exists := s.pMap[id]
return exists
}
type SessionCommand struct { type SessionCommand struct {
ID uuid.UUID `json:"player_id"` ID uuid.UUID `json:"player_id"`
MatchID uuid.UUID `json:"match_id"`
Command SessionCmd `json:"command"` Command SessionCmd `json:"command"`
GameCommand *game.Command `json:"game_command,omitempty"` GameCommand *game.Command `json:"game_command,omitempty"`
} }
@ -90,6 +100,7 @@ func (s *SessionCommand) String() string {
type SessionCommandResult struct { type SessionCommandResult struct {
ID uuid.UUID `json:"player_id"` ID uuid.UUID `json:"player_id"`
MatchID uuid.UUID `json:"match_id"`
Result SessionResp `json:"result"` Result SessionResp `json:"result"`
GameResult *game.CommandResult `json:"game_result,omitempty"` GameResult *game.CommandResult `json:"game_result,omitempty"`
} }