diff --git a/api_types/player_info.go b/api_types/player_info.go new file mode 100644 index 0000000..3fd1829 --- /dev/null +++ b/api_types/player_info.go @@ -0,0 +1 @@ +package api_types diff --git a/chess/match.go b/chess/game.go similarity index 81% rename from chess/match.go rename to chess/game.go index 70d7f63..1dc1146 100644 --- a/chess/match.go +++ b/chess/game.go @@ -8,8 +8,8 @@ import ( type Game struct { id uuid.UUID - players [2]Player - currentTurnPlayer Player + players []*Player + currentTurnPlayer *Player } const ( @@ -26,23 +26,24 @@ func NewGame() *Game { } func (game Game) getPlayer1() *Player { - return &game.players[0] + return game.players[0] } func (game Game) getPlayer2() *Player { - return &game.players[1] + return game.players[1] } -func (game *Game) handle() { +func (game *Game) Handle() { defer log.Println("Game ", game.id, ": handle() ended") + log.Println("Game ", game.id, " started") <-game.getPlayer1().wsConnEstablished log.Println("WS connection for player 1 established") <-game.getPlayer2().wsConnEstablished log.Println("WS connection for player 2 established") gameState := PlayerToMove - game.currentTurnPlayer = *game.getPlayer1() + game.currentTurnPlayer = game.getPlayer1() var move *Move var receivedMessage []byte @@ -96,14 +97,6 @@ func (game *Game) handle() { } } -func (game *Game) addPlayersToGame(players [2]Player) { - log.Printf("Adding players %s and %s to new game", players[0].Uuid.String(), players[1].Uuid.String()) - - for i := range players { - players[i].InGame = true - } - - game.players = players - - go game.handle() +func (game *Game) AddPlayersToGame(player *Player) { + game.players = append(game.players, player) } diff --git a/chess/lobby.go b/chess/lobby.go deleted file mode 100644 index 2e524c4..0000000 --- a/chess/lobby.go +++ /dev/null @@ -1,60 +0,0 @@ -package chess - -import ( - "sync" - - "github.com/google/uuid" -) - -type Lobby struct { - players map[uuid.UUID]*Player - mutex sync.Mutex -} - -var lobbyInstance *Lobby = nil - -func GetLobby() *Lobby { - if lobbyInstance == nil { - lobbyInstance = newLobby() - } - - return lobbyInstance -} - -func newLobby() *Lobby { - return &Lobby{ - players: make(map[uuid.UUID]*Player, 0), - } -} - -func (l *Lobby) RegisterPlayer(player *Player) { - l.players[player.Uuid] = player - - var playersToBeAddedToGame []Player - - for _, player := range l.players { - if !player.InGame { - playersToBeAddedToGame = append(playersToBeAddedToGame, *player) - } - } - - if len(playersToBeAddedToGame) < 2 { - return - } - - game := NewGame() - game.addPlayersToGame([2]Player(playersToBeAddedToGame[:2])) -} - -func (l *Lobby) GetPlayer(playerID uuid.UUID) (*Player, bool) { - player, found := l.players[playerID] - return player, found -} - -func (l *Lobby) Lock() { - l.mutex.Lock() -} - -func (l *Lobby) Unlock() { - l.mutex.Unlock() -} diff --git a/chess/player.go b/chess/player.go index cc49a39..a271e8e 100644 --- a/chess/player.go +++ b/chess/player.go @@ -14,12 +14,11 @@ type Player struct { InGame bool wsConnEstablished chan bool context context.Context - - JoinedLobby chan bool } type PlayerInfo struct { PlayerID uuid.UUID `json:"playerID"` + LobbyID uuid.UUID `json:"lobbyID"` } func NewPlayer(uuid uuid.UUID) *Player { @@ -28,7 +27,6 @@ func NewPlayer(uuid uuid.UUID) *Player { Conn: nil, InGame: false, wsConnEstablished: make(chan bool), - JoinedLobby: make(chan bool), } } diff --git a/lobby_registry/lobby.go b/lobby_registry/lobby.go index 1037ccc..db427dc 100644 --- a/lobby_registry/lobby.go +++ b/lobby_registry/lobby.go @@ -7,23 +7,43 @@ import ( ) type Lobby struct { - uuid uuid.UUID + Uuid uuid.UUID players []*chess.Player + + Game chess.Game + + PlayerJoined chan bool } -func NewEmptyLobbyByUUID(uuid uuid.UUID) *Lobby { - return &Lobby{uuid: uuid} +func NewEmptyLobbyWithUUID(uuid uuid.UUID) *Lobby { + return &Lobby{ + Uuid: uuid, + Game: *chess.NewGame(), + PlayerJoined: make(chan bool), + } } -func (w *Lobby) AddPlayer(player *chess.Player) { +func (w *Lobby) AddPlayerAndStartGameIfFull(player *chess.Player) { w.players = append(w.players, player) - player.JoinedLobby <- true + w.Game.AddPlayersToGame(player) + if w.IsFull() { + go w.Game.Handle() + } } func (w *Lobby) IsFull() bool { return len(w.players) == 2 } +func (l *Lobby) GetPlayerByUUID(uuid uuid.UUID) (*chess.Player, bool) { + for _, player := range l.players { + if player.Uuid == uuid { + return player, true + } + } + return nil, false +} + func (l *Lobby) GetPlayer1() *chess.Player { return l.players[0] } diff --git a/lobby_registry/registry.go b/lobby_registry/registry.go index 9449d16..954c0ee 100644 --- a/lobby_registry/registry.go +++ b/lobby_registry/registry.go @@ -29,13 +29,16 @@ func (r *LobbyRegistry) GetLobbyForPlayer() *Lobby { } } - newLobby := NewEmptyLobbyByUUID(uuid.New()) + newLobby := NewEmptyLobbyWithUUID(uuid.New()) r.addNewLobby(newLobby) return newLobby } -func (r *LobbyRegistry) addNewLobby(lobby *Lobby) uuid.UUID { - uuid := uuid.New() - r.lobbies[uuid] = lobby - return uuid +func (r *LobbyRegistry) GetLobbyByUUID(uuid uuid.UUID) *Lobby { + return r.lobbies[uuid] +} + +func (r *LobbyRegistry) addNewLobby(lobby *Lobby) uuid.UUID { + r.lobbies[lobby.Uuid] = lobby + return lobby.Uuid } diff --git a/main.go b/main.go index d4d5a43..b61bba6 100644 --- a/main.go +++ b/main.go @@ -2,11 +2,15 @@ package main import ( "context" + "encoding/json" + "fmt" "local/m/mchess_server/chess" + lobbies "local/m/mchess_server/lobby_registry" "local/m/mchess_server/usher" "log" "net/http" "os" + "sync" "github.com/gin-gonic/autotls" "github.com/gin-gonic/gin" @@ -37,41 +41,29 @@ func main() { } } +var mut sync.Mutex + func registerForRandomGame(c *gin.Context) { - - /* - What should be done: - 1. Register player - 2. Check if there is a game open that lacks one player - 3. Fill open game, then respond with player id and game id. - OR - - 1. Register player - 2. If there is no open game, open a game and wait for a second player to join - 3. Only after a second player joins, respond with player id and game id. - */ - player := chess.NewPlayer(uuid.New()) - usher := usher.GetUsher() + + mut.Lock() lobby := usher.WelcomeNewPlayer(player) - usher.AddPlayerToLobby(player, lobby) + usher.AddPlayerToLobbyAndStartGameIfFull(player, lobby) + mut.Unlock() - // Counter point to this approach: - // Waiting for two players might not be necessary. - // Just open the lobby and respond with lobby/game id and player id - // The waiting can be done in the game handler until both players opened a ws connection - usher.WaitForTwoPlayersInLobby(lobby) - - log.Println("responding with player id ", player.Uuid) - - c.IndentedJSON(http.StatusOK, chess.PlayerInfo{ + info := chess.PlayerInfo{ PlayerID: player.Uuid, - }) + LobbyID: lobby.Uuid, + } + log.Println("responding with info ", info) + + c.Header("Access-Control-Allow-Origin", "*") + c.IndentedJSON(http.StatusOK, info) } func registerWebSocketConnection(c *gin.Context) { - webSocketConn, err := websocket.Accept(c.Writer, c.Request, nil) + webSocketConn, err := websocket.Accept(c.Writer, c.Request, &websocket.AcceptOptions{OriginPatterns: []string{"localhost:*"}}) if err != nil { log.Println(err) return @@ -80,23 +72,27 @@ func registerWebSocketConnection(c *gin.Context) { } func waitForAndHandlePlayerID(ctx context.Context, conn websocket.Conn) { - msgType, id, err := conn.Read(ctx) - - log.Println("read from websocket: ", msgType, id, err) - log.Println("id as string", string(id)) - - uuid, err := uuid.ParseBytes(id) + msgType, msg, err := conn.Read(ctx) if err != nil { - log.Println(err) - conn.Close(websocket.StatusCode(400), err.Error()) + errorMessage := fmt.Sprintf("Reading from websocket connection did not work: %s", err) + log.Println(errorMessage) + conn.Close(websocket.StatusCode(400), errorMessage) return } - // since we cannot use the lobby anymore (it does not exist anymore after this change) the client needs to - // send game id and player id so we can make the connection to the player - //lobby := chess.GetLobby() + log.Println("read from websocket: ", msgType, string(msg), err) - player, found := lobby.GetPlayer(uuid) + var info chess.PlayerInfo + err = json.Unmarshal(msg, &info) + if err != nil { + errorMessage := fmt.Sprintf("Unmarshaling message did not work: %s", err) + log.Println(errorMessage) + conn.Close(websocket.StatusCode(400), errorMessage) + return + } + + lobby := lobbies.GetLobbyRegistry().GetLobbyByUUID(info.LobbyID) + player, found := lobby.GetPlayerByUUID(info.PlayerID) if !found { conn.Close(websocket.StatusCode(400), "player not found") return diff --git a/usher/usher.go b/usher/usher.go index e612392..57e81a5 100644 --- a/usher/usher.go +++ b/usher/usher.go @@ -26,14 +26,6 @@ func (u *Usher) WelcomeNewPlayer(player *chess.Player) *lobbies.Lobby { return lobby } -func (u *Usher) AddPlayerToLobby(player *chess.Player, lobby *lobbies.Lobby) { - lobby.AddPlayer(player) -} - -func (u *Usher) WaitForTwoPlayersInLobby(lobby *lobbies.Lobby) { - player1 := lobby.GetPlayer1() - <-player1.JoinedLobby - - player2 := lobby.GetPlayer2() - <-player2.JoinedLobby +func (u *Usher) AddPlayerToLobbyAndStartGameIfFull(player *chess.Player, lobby *lobbies.Lobby) { + lobby.AddPlayerAndStartGameIfFull(player) }