diff --git a/internal/coordinator/match.go b/internal/coordinator/match.go new file mode 100644 index 0000000..f0cbf6e --- /dev/null +++ b/internal/coordinator/match.go @@ -0,0 +1,162 @@ +package coordinator + +import ( + "log" + "time" + + "git.saintnet.tech/stryan/snengame/internal/game" + "github.com/google/uuid" +) + +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) + for { + select { + case p := <-c.PlayerQueueChan: + //add player to pool + pool[p] = 0 + log.Printf("Player %v has queued", p) + default: + //no new players, let's try to matchmake + if len(pool) < 2 { + continue + } else { + //fancy matchmaking math to guarantee a fair game + var p1, p2 uuid.UUID + for key, _ := range pool { + p1 = key + break + } + delete(pool, p1) + for key, _ := range pool { + p2 = key + break + } + delete(pool, p2) + m := NewSession() + log.Printf("Creating match %v for %v and %v", m.ID, p1, p2) + m.Active = true + m.Game = game.NewGame() + c.MatchLock.Lock() + c.Matches[m.ID] = m + c.MatchLock.Unlock() + c.CallbackChan[p1] <- m.ID + c.CallbackChan[p2] <- m.ID + go MatchWatcher(m) + } + + } + } +} + +func MatchCleaner(c *Coordinator) { + for { + time.Sleep(10 * time.Second) + c.MatchLock.Lock() + for _, v := range c.Matches { + if v.Game == nil && v.Active { + log.Println("clearing match with no game") + delete(c.Matches, v.ID) + v.Watcher <- true + } + } + c.MatchLock.Unlock() + } +} + +func MatchWatcher(m *Session) { + ticker := time.NewTicker(1 * time.Second) + old_turn := -1 + var old_board *game.Board + old_sen_hand := -1 + old_sco_hand := -1 + old_sen_life := -1 + old_sco_life := -1 + sen_ready := false + sco_ready := false + for { + select { + case <-ticker.C: + if m.Active && m.Game != nil && len(m.Broadcasts) > 0 { + if m.Game.Status == game.StatusLobby && !sen_ready && m.Game.SentinalPlayer.Ready { + for _, v := range m.Broadcasts { + addBroadcast(v, SessionRespBroadcastSenReady) + } + sen_ready = true + } + if m.Game.Status == game.StatusLobby && !sco_ready && m.Game.ScourgePlayer.Ready { + for _, v := range m.Broadcasts { + addBroadcast(v, SessionRespBroadcastScoReady) + } + sco_ready = true + } + if m.Game.Status == game.StatusSentinalWin { + for _, v := range m.Broadcasts { + addBroadcast(v, SessionRespBroadcastSenWin) + } + } + if m.Game.Status == game.StatusScourgeWin { + for _, v := range m.Broadcasts { + addBroadcast(v, SessionRespBroadcastScoWin) + } + } + if m.p1 == uuid.Nil && sen_ready { + for _, v := range m.Broadcasts { + addBroadcast(v, SessionRespBroadcastSenLeft) + } + sen_ready = false + } + if m.p2 == uuid.Nil && sco_ready { + for _, v := range m.Broadcasts { + addBroadcast(v, SessionRespBroadcastScoLeft) + } + sco_ready = false + } + if old_board == nil || old_board.Sentinal != m.Game.GameBoard.Sentinal || old_board.Scourge != m.Game.GameBoard.Scourge || old_sen_hand != len(m.Game.SentinalPlayer.Hand) || old_sco_hand != len(m.Game.ScourgePlayer.Hand) || old_sen_life != m.Game.SentinalPlayer.Life || old_sco_life != m.Game.ScourgePlayer.Life { + if old_board == nil { + old_board = m.Game.GameBoard + } else { + old_board.Sentinal = m.Game.GameBoard.Sentinal + old_board.Scourge = m.Game.GameBoard.Scourge + } + old_sen_hand = len(m.Game.SentinalPlayer.Hand) + old_sco_hand = len(m.Game.ScourgePlayer.Hand) + old_sen_life = m.Game.SentinalPlayer.Life + old_sco_life = m.Game.ScourgePlayer.Life + for _, v := range m.Broadcasts { + addBroadcast(v, SessionRespBroadcastUpdate) + } + } + if old_turn != m.Game.CurrentTurn { + old_turn = m.Game.CurrentTurn + if old_turn == game.SentinalID { + for k, v := range m.pMap { + if v == game.SentinalID { + addBroadcast(m.Broadcasts[k], SessionRespBroadcastSenTurn) + } + } + } else if old_turn == game.ScourgeID { + for k, v := range m.pMap { + if v == game.ScourgeID { + addBroadcast(m.Broadcasts[k], SessionRespBroadcastScoTrun) + } + } + } + } + } + + case <-m.Watcher: + close(m.Watcher) + return + } + } +} + +func addBroadcast(pipe chan SessionResp, brd SessionResp) { + select { + case pipe <- brd: + default: + log.Println("broadcasts buffer full, discarding") + } +}