package coordinator import ( "fmt" "time" "git.saintnet.tech/stryan/snengame/internal/game" "github.com/google/uuid" ) type SessionCmd string type SessionResp string const ( SessionCmdQuery SessionCmd = "query" SessionCmdJoin = "join" SessionCmdLeave = "leave" SessionCmdPlay = "play" SessionCmdPoll = "poll" SessionCmdReady = "ready" ) const ( SessionRespFound SessionResp = "found" SessionRespJoined1 = "joined p1" SessionRespJoined2 = "joined p2" SessionRespReady = "game ready" SessionRespJoinError = "join error" SessionRespLeft = "left" SessionRespPlayed = "played" SessionRespError = "generic error" SessionRespBroadcastSenTurn = "Sentinal turn" SessionRespBroadcastScoTrun = "Scourge turn" SessionRespBroadcastSenWin = "Sentinal wins" SessionRespBroadcastScoWin = "Scourge wins" SessionRespBroadcastUpdate = "update" SessionRespBroadcastSenJoin = "Sentinal joined" SessionRespBroadcastScoJoin = "Scourge joined" SessionRespBroadcastSenReady = "Sentinal player is ready" SessionRespBroadcastScoReady = "Scourge player is ready" SessionRespBroadcastSenLeft = "Sentinal player has left" SessionRespBroadcastScoLeft = "Scourge player has left" SessionRespBroadcastNone = "" ) type Session struct { ID uuid.UUID p1 uuid.UUID p2 uuid.UUID pMap map[uuid.UUID]int Active bool Game *game.Game Watcher chan bool Broadcasts map[uuid.UUID]chan SessionResp LastMove time.Time } func NewSession() *Session { return &Session{ ID: uuid.New(), p1: uuid.Nil, p2: uuid.Nil, pMap: make(map[uuid.UUID]int), Active: false, Game: nil, Watcher: make(chan bool), Broadcasts: make(map[uuid.UUID]chan SessionResp), LastMove: time.Now(), } } func (s *Session) Join(id uuid.UUID) SessionResp { if s.p1 == uuid.Nil { s.p1 = id s.pMap[id] = game.SentinalID for _, v := range s.Broadcasts { v <- SessionRespBroadcastSenJoin } return SessionRespJoined1 } else if s.p2 == uuid.Nil { s.p2 = id s.pMap[id] = game.ScourgeID for _, v := range s.Broadcasts { v <- SessionRespBroadcastScoJoin } return SessionRespJoined2 } else { return SessionRespJoinError } } func (s *Session) Leave(id uuid.UUID) { if id == s.p1 { s.p1 = uuid.Nil } else if id == s.p2 { s.p2 = uuid.Nil } delete(s.Broadcasts, id) if s.p1 == uuid.Nil && s.p2 == uuid.Nil { s.Game = nil } else if s.Game.Status != game.StatusDraw || s.Game.Status != game.StatusScourgeWin || s.Game.Status != game.StatusSentinalWin { s.Game.Status = game.StatusStop } } func (s *Session) Play(id uuid.UUID, cmd *game.Command) *game.CommandResult { if s.pMap[id] != cmd.PlayerID { return nil } if cmd.Type != SessionCmdPoll { s.LastMove = time.Now() } res := s.Game.Parse(cmd) return res } func (s *Session) PlayerIn(id uuid.UUID) bool { _, exists := s.pMap[id] return exists } type SessionCommand struct { ID uuid.UUID `json:"player_id"` MatchID uuid.UUID `json:"match_id"` Command SessionCmd `json:"command"` GameCommand *game.Command `json:"game_command,omitempty"` } func (s *SessionCommand) String() string { return fmt.Sprintf("%v %v %v\n", s.ID, s.Command, s.GameCommand) } type SessionCommandResult struct { ID uuid.UUID `json:"player_id"` MatchID uuid.UUID `json:"match_id"` Result SessionResp `json:"result"` GameResult *game.CommandResult `json:"game_result,omitempty"` } func (s *SessionCommandResult) String() string { return fmt.Sprintf("%v %v %v\n", s.ID, s.Result, s.GameResult) }