162 lines
3.6 KiB
Go
162 lines
3.6 KiB
Go
|
package coordinator
|
||
|
|
||
|
import (
|
||
|
"log"
|
||
|
"sync"
|
||
|
"time"
|
||
|
|
||
|
"git.saintnet.tech/tomecraft/tome_game"
|
||
|
. "git.saintnet.tech/tomecraft/tome_lib"
|
||
|
"github.com/google/uuid"
|
||
|
)
|
||
|
|
||
|
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
|
||
|
}
|
||
|
|
||
|
func NewCoordinator() *Coordinator {
|
||
|
return &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),
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (c *Coordinator) Start() {
|
||
|
go MatchMaker(c)
|
||
|
go MatchCleaner(c)
|
||
|
go QueueCleaner(c)
|
||
|
}
|
||
|
|
||
|
func (c *Coordinator) Coordinate(cmd *SessionCommand) *SessionCommandResult {
|
||
|
switch cmd.Command {
|
||
|
case SessionCmdQuery:
|
||
|
c.CallbackChan[cmd.ID] = make(chan uuid.UUID)
|
||
|
c.PlayerQueueChan <- cmd.ID
|
||
|
ticker := time.NewTicker(5 * time.Minute)
|
||
|
select {
|
||
|
case m := <-c.CallbackChan[cmd.ID]:
|
||
|
return &SessionCommandResult{
|
||
|
ID: cmd.ID,
|
||
|
MatchID: m,
|
||
|
Result: SessionRespFound,
|
||
|
}
|
||
|
case <-ticker.C:
|
||
|
return &SessionCommandResult{
|
||
|
ID: cmd.ID,
|
||
|
MatchID: uuid.Nil,
|
||
|
Result: SessionRespError,
|
||
|
}
|
||
|
}
|
||
|
case SessionCmdJoin:
|
||
|
m, exists := c.Matches[cmd.MatchID]
|
||
|
if !exists {
|
||
|
log.Printf("player %v tried to join non-existent match %v", cmd.ID, cmd.MatchID)
|
||
|
return &SessionCommandResult{
|
||
|
ID: cmd.ID,
|
||
|
MatchID: uuid.Nil,
|
||
|
Result: SessionRespJoinError,
|
||
|
}
|
||
|
}
|
||
|
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 = tome_game.NewGame()
|
||
|
m.Active = true
|
||
|
}
|
||
|
return &SessionCommandResult{
|
||
|
ID: cmd.ID,
|
||
|
MatchID: m.ID,
|
||
|
Result: resp,
|
||
|
}
|
||
|
case SessionCmdReady:
|
||
|
m, exists := c.Matches[cmd.MatchID]
|
||
|
if !exists {
|
||
|
return &SessionCommandResult{
|
||
|
ID: cmd.ID,
|
||
|
MatchID: uuid.Nil,
|
||
|
Result: SessionRespError,
|
||
|
}
|
||
|
}
|
||
|
if m.p1 != uuid.Nil && m.p2 != uuid.Nil {
|
||
|
return &SessionCommandResult{
|
||
|
ID: cmd.ID,
|
||
|
MatchID: m.ID,
|
||
|
Result: SessionRespReady,
|
||
|
}
|
||
|
} else {
|
||
|
return &SessionCommandResult{
|
||
|
ID: cmd.ID,
|
||
|
MatchID: uuid.Nil,
|
||
|
Result: SessionRespError,
|
||
|
}
|
||
|
}
|
||
|
case SessionCmdLeave:
|
||
|
m, exists := c.Matches[cmd.MatchID]
|
||
|
if exists && m.PlayerIn(cmd.ID) {
|
||
|
m.Leave(cmd.ID)
|
||
|
} else {
|
||
|
for k, _ := range c.PlayerPool {
|
||
|
if k.Id == m.ID {
|
||
|
delete(c.PlayerPool, k)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return &SessionCommandResult{
|
||
|
ID: cmd.ID,
|
||
|
MatchID: uuid.Nil,
|
||
|
Result: SessionRespLeft,
|
||
|
}
|
||
|
case SessionCmdPlay:
|
||
|
m, exists := c.Matches[cmd.MatchID]
|
||
|
if !exists || !m.PlayerIn(cmd.ID) || m.Game == nil {
|
||
|
return &SessionCommandResult{
|
||
|
ID: cmd.ID,
|
||
|
MatchID: uuid.Nil,
|
||
|
Result: SessionRespError,
|
||
|
}
|
||
|
}
|
||
|
resp := m.Play(cmd.ID, cmd.GameCommand)
|
||
|
return &SessionCommandResult{
|
||
|
ID: cmd.ID,
|
||
|
MatchID: m.ID,
|
||
|
Result: SessionRespPlayed,
|
||
|
GameResult: resp,
|
||
|
}
|
||
|
case SessionCmdPoll:
|
||
|
m, exists := c.Matches[cmd.MatchID]
|
||
|
if exists {
|
||
|
_, exists = m.Broadcasts[cmd.ID]
|
||
|
if !exists {
|
||
|
log.Printf("%v has opted in to polling", cmd.ID)
|
||
|
m.Broadcasts[cmd.ID] = make(chan SessionResp, 10)
|
||
|
}
|
||
|
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,
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return &SessionCommandResult{
|
||
|
ID: cmd.ID,
|
||
|
MatchID: uuid.Nil,
|
||
|
Result: SessionRespError,
|
||
|
}
|
||
|
}
|