Scrap 2-player waiting room and make it simple.

This commit is contained in:
Marco 2023-06-02 21:14:02 +02:00
parent aac428baab
commit 78ddd4f90f
8 changed files with 80 additions and 137 deletions

1
api_types/player_info.go Normal file
View File

@ -0,0 +1 @@
package api_types

View File

@ -8,8 +8,8 @@ import (
type Game struct { type Game struct {
id uuid.UUID id uuid.UUID
players [2]Player players []*Player
currentTurnPlayer Player currentTurnPlayer *Player
} }
const ( const (
@ -26,23 +26,24 @@ func NewGame() *Game {
} }
func (game Game) getPlayer1() *Player { func (game Game) getPlayer1() *Player {
return &game.players[0] return game.players[0]
} }
func (game Game) getPlayer2() *Player { 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") defer log.Println("Game ", game.id, ": handle() ended")
log.Println("Game ", game.id, " started")
<-game.getPlayer1().wsConnEstablished <-game.getPlayer1().wsConnEstablished
log.Println("WS connection for player 1 established") log.Println("WS connection for player 1 established")
<-game.getPlayer2().wsConnEstablished <-game.getPlayer2().wsConnEstablished
log.Println("WS connection for player 2 established") log.Println("WS connection for player 2 established")
gameState := PlayerToMove gameState := PlayerToMove
game.currentTurnPlayer = *game.getPlayer1() game.currentTurnPlayer = game.getPlayer1()
var move *Move var move *Move
var receivedMessage []byte var receivedMessage []byte
@ -96,14 +97,6 @@ func (game *Game) handle() {
} }
} }
func (game *Game) addPlayersToGame(players [2]Player) { func (game *Game) AddPlayersToGame(player *Player) {
log.Printf("Adding players %s and %s to new game", players[0].Uuid.String(), players[1].Uuid.String()) game.players = append(game.players, player)
for i := range players {
players[i].InGame = true
}
game.players = players
go game.handle()
} }

View File

@ -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()
}

View File

@ -14,12 +14,11 @@ type Player struct {
InGame bool InGame bool
wsConnEstablished chan bool wsConnEstablished chan bool
context context.Context context context.Context
JoinedLobby chan bool
} }
type PlayerInfo struct { type PlayerInfo struct {
PlayerID uuid.UUID `json:"playerID"` PlayerID uuid.UUID `json:"playerID"`
LobbyID uuid.UUID `json:"lobbyID"`
} }
func NewPlayer(uuid uuid.UUID) *Player { func NewPlayer(uuid uuid.UUID) *Player {
@ -28,7 +27,6 @@ func NewPlayer(uuid uuid.UUID) *Player {
Conn: nil, Conn: nil,
InGame: false, InGame: false,
wsConnEstablished: make(chan bool), wsConnEstablished: make(chan bool),
JoinedLobby: make(chan bool),
} }
} }

View File

@ -7,23 +7,43 @@ import (
) )
type Lobby struct { type Lobby struct {
uuid uuid.UUID Uuid uuid.UUID
players []*chess.Player players []*chess.Player
Game chess.Game
PlayerJoined chan bool
} }
func NewEmptyLobbyByUUID(uuid uuid.UUID) *Lobby { func NewEmptyLobbyWithUUID(uuid uuid.UUID) *Lobby {
return &Lobby{uuid: uuid} 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) 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 { func (w *Lobby) IsFull() bool {
return len(w.players) == 2 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 { func (l *Lobby) GetPlayer1() *chess.Player {
return l.players[0] return l.players[0]
} }

View File

@ -29,13 +29,16 @@ func (r *LobbyRegistry) GetLobbyForPlayer() *Lobby {
} }
} }
newLobby := NewEmptyLobbyByUUID(uuid.New()) newLobby := NewEmptyLobbyWithUUID(uuid.New())
r.addNewLobby(newLobby) r.addNewLobby(newLobby)
return newLobby return newLobby
} }
func (r *LobbyRegistry) addNewLobby(lobby *Lobby) uuid.UUID { func (r *LobbyRegistry) GetLobbyByUUID(uuid uuid.UUID) *Lobby {
uuid := uuid.New() return r.lobbies[uuid]
r.lobbies[uuid] = lobby }
return uuid
func (r *LobbyRegistry) addNewLobby(lobby *Lobby) uuid.UUID {
r.lobbies[lobby.Uuid] = lobby
return lobby.Uuid
} }

72
main.go
View File

@ -2,11 +2,15 @@ package main
import ( import (
"context" "context"
"encoding/json"
"fmt"
"local/m/mchess_server/chess" "local/m/mchess_server/chess"
lobbies "local/m/mchess_server/lobby_registry"
"local/m/mchess_server/usher" "local/m/mchess_server/usher"
"log" "log"
"net/http" "net/http"
"os" "os"
"sync"
"github.com/gin-gonic/autotls" "github.com/gin-gonic/autotls"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
@ -37,41 +41,29 @@ func main() {
} }
} }
var mut sync.Mutex
func registerForRandomGame(c *gin.Context) { 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()) player := chess.NewPlayer(uuid.New())
usher := usher.GetUsher() usher := usher.GetUsher()
mut.Lock()
lobby := usher.WelcomeNewPlayer(player) lobby := usher.WelcomeNewPlayer(player)
usher.AddPlayerToLobby(player, lobby) usher.AddPlayerToLobbyAndStartGameIfFull(player, lobby)
mut.Unlock()
// Counter point to this approach: info := chess.PlayerInfo{
// 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{
PlayerID: player.Uuid, 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) { 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 { if err != nil {
log.Println(err) log.Println(err)
return return
@ -80,23 +72,27 @@ func registerWebSocketConnection(c *gin.Context) {
} }
func waitForAndHandlePlayerID(ctx context.Context, conn websocket.Conn) { func waitForAndHandlePlayerID(ctx context.Context, conn websocket.Conn) {
msgType, id, err := conn.Read(ctx) msgType, msg, err := conn.Read(ctx)
log.Println("read from websocket: ", msgType, id, err)
log.Println("id as string", string(id))
uuid, err := uuid.ParseBytes(id)
if err != nil { if err != nil {
log.Println(err) errorMessage := fmt.Sprintf("Reading from websocket connection did not work: %s", err)
conn.Close(websocket.StatusCode(400), err.Error()) log.Println(errorMessage)
conn.Close(websocket.StatusCode(400), errorMessage)
return return
} }
// since we cannot use the lobby anymore (it does not exist anymore after this change) the client needs to log.Println("read from websocket: ", msgType, string(msg), err)
// send game id and player id so we can make the connection to the player
//lobby := chess.GetLobby()
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 { if !found {
conn.Close(websocket.StatusCode(400), "player not found") conn.Close(websocket.StatusCode(400), "player not found")
return return

View File

@ -26,14 +26,6 @@ func (u *Usher) WelcomeNewPlayer(player *chess.Player) *lobbies.Lobby {
return lobby return lobby
} }
func (u *Usher) AddPlayerToLobby(player *chess.Player, lobby *lobbies.Lobby) { func (u *Usher) AddPlayerToLobbyAndStartGameIfFull(player *chess.Player, lobby *lobbies.Lobby) {
lobby.AddPlayer(player) lobby.AddPlayerAndStartGameIfFull(player)
}
func (u *Usher) WaitForTwoPlayersInLobby(lobby *lobbies.Lobby) {
player1 := lobby.GetPlayer1()
<-player1.JoinedLobby
player2 := lobby.GetPlayer2()
<-player2.JoinedLobby
} }