diff --git a/internal/coordinator/coordinator.go b/internal/coordinator/coordinator.go index c544181..ad99dd3 100644 --- a/internal/coordinator/coordinator.go +++ b/internal/coordinator/coordinator.go @@ -5,6 +5,7 @@ import ( "sync" "time" + "git.saintnet.tech/stryan/snengame/internal/game" "github.com/google/uuid" ) @@ -12,6 +13,7 @@ type Coordinator struct { Matches map[uuid.UUID]*Session MatchLock *sync.Mutex PlayerQueueChan chan uuid.UUID + PlayerPool map[MMRPlayer]bool CallbackChan map[uuid.UUID]chan uuid.UUID } @@ -20,6 +22,7 @@ func NewCoordinator() *Coordinator { Matches: make(map[uuid.UUID]*Session), MatchLock: &sync.Mutex{}, PlayerQueueChan: make(chan uuid.UUID), + PlayerPool: make(map[MMRPlayer]bool), CallbackChan: make(map[uuid.UUID]chan uuid.UUID), } } @@ -27,6 +30,7 @@ func NewCoordinator() *Coordinator { func (c *Coordinator) Start() { go MatchMaker(c) go MatchCleaner(c) + go QueueCleaner(c) } func (c *Coordinator) Coordinate(cmd *SessionCommand) *SessionCommandResult { @@ -60,6 +64,11 @@ func (c *Coordinator) Coordinate(cmd *SessionCommand) *SessionCommandResult { } } resp := m.Join(cmd.ID) + if m.p1 != uuid.Nil && m.p2 != uuid.Nil { + log.Printf("Starting game for %v and %v\n", m.p1, m.p2) + m.Game = game.NewGame() + m.Active = true + } return &SessionCommandResult{ ID: cmd.ID, MatchID: m.ID, diff --git a/internal/coordinator/match.go b/internal/coordinator/match.go index 5bc49f7..bea5882 100644 --- a/internal/coordinator/match.go +++ b/internal/coordinator/match.go @@ -8,41 +8,48 @@ import ( "github.com/google/uuid" ) +type MMRPlayer struct { + Id uuid.UUID + MMR int + QueueTime time.Time +} + func MatchMaker(c *Coordinator) { - //in the future the int below will be MMR or something, but for now it's just a set - pool := make(map[uuid.UUID]int) + //in the future the int will be MMR or something, but for now it's just a set for { select { case p := <-c.PlayerQueueChan: //add player to pool - pool[p] = 0 + c.PlayerPool[MMRPlayer{ + Id: p, + MMR: 0, + QueueTime: time.Now()}] = true log.Printf("Player %v has queued", p) default: //no new players, let's try to matchmake - if len(pool) < 2 { + if len(c.PlayerPool) < 2 { continue } else { //fancy matchmaking math to guarantee a fair game - var p1, p2 uuid.UUID - for key, _ := range pool { + var p1, p2 MMRPlayer + for key, _ := range c.PlayerPool { p1 = key break } - delete(pool, p1) - for key, _ := range pool { + delete(c.PlayerPool, p1) + for key, _ := range c.PlayerPool { p2 = key break } - delete(pool, p2) + delete(c.PlayerPool, p2) m := NewSession() log.Printf("Creating match %v for %v and %v", m.ID, p1, p2) - m.Active = true - m.Game = game.NewGame() + m.Active = false c.MatchLock.Lock() c.Matches[m.ID] = m c.MatchLock.Unlock() - c.CallbackChan[p1] <- m.ID - c.CallbackChan[p2] <- m.ID + c.CallbackChan[p1.Id] <- m.ID + c.CallbackChan[p2.Id] <- m.ID go MatchWatcher(m) } @@ -50,6 +57,18 @@ func MatchMaker(c *Coordinator) { } } +func QueueCleaner(c *Coordinator) { + for { + time.Sleep(5 * time.Minute) + for v, _ := range c.PlayerPool { + if time.Now().After(v.QueueTime.Add(time.Minute * 5)) { + log.Printf("Removing player %v from pool", v.Id) + delete(c.PlayerPool, v) //probably should just flag + } + } + } +} + func MatchCleaner(c *Coordinator) { for { time.Sleep(10 * time.Second)