snengame/internal/coordinator/coordinator.go

189 lines
4.0 KiB
Go
Raw Normal View History

2021-07-22 18:19:21 -04:00
package coordinator
import (
"fmt"
"log"
2021-07-25 17:39:48 -04:00
"sync"
2021-07-22 18:19:21 -04:00
"time"
"git.saintnet.tech/stryan/snengame/internal/game"
"github.com/google/uuid"
)
type Coordinator struct {
Matches map[uuid.UUID]*Session
2021-07-25 17:39:48 -04:00
MatchLock *sync.Mutex
2021-07-22 18:19:21 -04:00
PlayerQueueChan chan uuid.UUID
CallbackChan map[uuid.UUID]chan uuid.UUID
2021-07-22 18:19:21 -04:00
}
func NewCoordinator() *Coordinator {
return &Coordinator{
Matches: make(map[uuid.UUID]*Session),
2021-07-25 17:39:48 -04:00
MatchLock: &sync.Mutex{},
2021-07-22 18:19:21 -04:00
PlayerQueueChan: make(chan uuid.UUID),
CallbackChan: make(map[uuid.UUID]chan uuid.UUID),
2021-07-22 18:19:21 -04:00
}
}
func (c *Coordinator) Start() {
go func() {
2021-07-25 17:39:48 -04:00
for {
m := NewSession()
var p1, p2 uuid.UUID
p1 = <-c.PlayerQueueChan
fmt.Println("p1 join")
p2 = <-c.PlayerQueueChan
fmt.Println("p2 join")
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
2021-07-26 13:02:00 -04:00
go MatchWatcher(m)
2021-07-25 17:39:48 -04:00
}
2021-07-22 18:19:21 -04:00
}()
go func() {
for {
2021-07-25 17:39:48 -04:00
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)
2021-07-26 13:02:00 -04:00
v.Watcher <- true
}
}
2021-07-25 17:39:48 -04:00
c.MatchLock.Unlock()
2021-07-22 18:19:21 -04:00
}
}()
}
func (c *Coordinator) Coordinate(cmd *SessionCommand) *SessionCommandResult {
switch cmd.Command {
case SessionCmdQuery:
c.CallbackChan[cmd.ID] = make(chan uuid.UUID)
2021-07-22 18:19:21 -04:00
c.PlayerQueueChan <- cmd.ID
m := <-c.CallbackChan[cmd.ID]
2021-07-22 18:19:21 -04:00
return &SessionCommandResult{
ID: cmd.ID,
MatchID: m,
Result: SessionRespFound,
2021-07-22 18:19:21 -04:00
}
case SessionCmdJoin:
m, exists := c.Matches[cmd.MatchID]
if !exists {
2021-07-25 16:23:39 -04:00
return &SessionCommandResult{
ID: cmd.ID,
MatchID: uuid.Nil,
Result: SessionRespJoinError,
2021-07-25 16:23:39 -04:00
}
}
resp := m.Join(cmd.ID)
2021-07-22 18:19:21 -04:00
return &SessionCommandResult{
ID: cmd.ID,
MatchID: m.ID,
Result: resp,
2021-07-22 18:19:21 -04:00
}
case SessionCmdLeave:
m, exists := c.Matches[cmd.MatchID]
if !exists || !m.PlayerIn(cmd.ID) {
2021-07-25 16:23:39 -04:00
return &SessionCommandResult{
ID: cmd.ID,
MatchID: uuid.Nil,
Result: SessionRespLeft,
2021-07-25 16:23:39 -04:00
}
}
m.Leave(cmd.ID)
2021-07-22 18:19:21 -04:00
return &SessionCommandResult{
ID: cmd.ID,
MatchID: uuid.Nil,
Result: SessionRespLeft,
2021-07-22 18:19:21 -04:00
}
case SessionCmdPlay:
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)
2021-07-22 18:19:21 -04:00
return &SessionCommandResult{
ID: cmd.ID,
MatchID: m.ID,
2021-07-22 18:19:21 -04:00
Result: SessionRespPlayed,
GameResult: resp,
}
2021-07-26 13:02:00 -04:00
case SessionCmdPoll:
m, exists := c.Matches[cmd.MatchID]
if exists {
select {
case res := <-m.Broadcasts[cmd.ID]:
return &SessionCommandResult{
ID: cmd.ID,
MatchID: m.ID,
Result: res,
}
default:
return &SessionCommandResult{
ID: cmd.ID,
MatchID: m.ID,
Result: SessionRespBroadcastNone,
}
}
}
2021-07-22 18:19:21 -04:00
}
return &SessionCommandResult{
ID: cmd.ID,
MatchID: uuid.Nil,
Result: SessionRespError,
2021-07-22 18:19:21 -04:00
}
}
2021-07-26 13:02:00 -04:00
func MatchWatcher(m *Session) {
ticker := time.NewTicker(1 * time.Second)
old_turn := -1
for {
select {
case <-ticker.C:
if m.Active && m.Game != nil {
if m.Game.Status == game.StatusSentinalWin {
for _, v := range m.Broadcasts {
v <- SessionRespBroadcastSenWin
}
}
if m.Game.Status == game.StatusScourgeWin {
for _, v := range m.Broadcasts {
v <- SessionRespBroadcastScoWin
}
}
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 {
m.Broadcasts[k] <- SessionRespBroadcastSenTurn
}
}
} else if old_turn == game.ScourgeID {
for k, v := range m.pMap {
if v == game.ScourgeID {
m.Broadcasts[k] <- SessionRespBroadcastScoTrun
}
}
}
}
}
case <-m.Watcher:
close(m.Watcher)
return
}
}
}