Various changes

1. Make lobby a struct containing the players and a mutex used to lock
   itself
2. Wait for websocket connections to be established by both players
   before starting the game.
3. Add methods to write to and read from players
This commit is contained in:
Marco 2023-05-30 22:01:20 +02:00
parent 5b6cb566ec
commit 6cbd7d37aa
5 changed files with 89 additions and 44 deletions

13
main.go
View File

@ -37,9 +37,12 @@ func main() {
} }
func registerForRandomGame(c *gin.Context) { func registerForRandomGame(c *gin.Context) {
player := server.NewPlayer(uuid.New()) player := server.NewPlayer(uuid.New())
lobby := server.GetLobby()
lobby.Lock()
server.GetLobby().RegisterPlayer(player) server.GetLobby().RegisterPlayer(player)
lobby.Unlock()
log.Println("responding with player id ", player.Uuid) log.Println("responding with player id ", player.Uuid)
@ -49,7 +52,6 @@ func registerForRandomGame(c *gin.Context) {
} }
func registerWebSocketConnection(c *gin.Context) { func registerWebSocketConnection(c *gin.Context) {
// w http.ResponseWriter, r *http.Request
webSocketConn, err := websocket.Accept(c.Writer, c.Request, nil) webSocketConn, err := websocket.Accept(c.Writer, c.Request, nil)
if err != nil { if err != nil {
log.Println(err) log.Println(err)
@ -59,8 +61,6 @@ func registerWebSocketConnection(c *gin.Context) {
} }
func waitForAndHandlePlayerID(ctx context.Context, conn websocket.Conn) { func waitForAndHandlePlayerID(ctx context.Context, conn websocket.Conn) {
// var playerInfo server.PlayerInfo
msgType, id, err := conn.Read(ctx) msgType, id, err := conn.Read(ctx)
log.Println("read from websocket: ", msgType, id, err) log.Println("read from websocket: ", msgType, id, err)
@ -74,7 +74,7 @@ func waitForAndHandlePlayerID(ctx context.Context, conn websocket.Conn) {
} }
lobby := server.GetLobby() lobby := server.GetLobby()
player, found := lobby[uuid] player, found := lobby.GetPlayer(uuid)
if !found { if !found {
conn.Close(websocket.StatusCode(400), "player not found") conn.Close(websocket.StatusCode(400), "player not found")
return return
@ -82,5 +82,6 @@ func waitForAndHandlePlayerID(ctx context.Context, conn websocket.Conn) {
if player.Conn != nil { if player.Conn != nil {
player.Conn.Close(websocket.StatusCode(400), "closing existing connection") player.Conn.Close(websocket.StatusCode(400), "closing existing connection")
} }
player.Conn = &conn player.SetConnection(ctx, conn)
log.Println("player after setting connection: ", player)
} }

View File

@ -25,13 +25,25 @@ func NewGame() *Game {
return &game return &game
} }
func (game Game) getPlayer1() *Player {
return &game.players[0]
}
func (game Game) getPlayer2() *Player {
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")
<-game.getPlayer1().wsConnEstablished
log.Println("WS connection for player 1 established")
<-game.getPlayer2().wsConnEstablished
log.Println("WS connection for player 2 established")
gameState := PlayerToMove gameState := PlayerToMove
game.currentTurnPlayer = game.players[0] game.currentTurnPlayer = *game.getPlayer1()
var move *Move var move *Move
var messageType int
var receivedMessage []byte var receivedMessage []byte
for { for {
@ -39,7 +51,7 @@ func (game *Game) handle() {
switch gameState { switch gameState {
case PlayerToMove: case PlayerToMove:
var err error var err error
messageType, receivedMessage, err = ReadMessageFromPlayer(&game.currentTurnPlayer) _, receivedMessage, err = game.currentTurnPlayer.ReadMessageFromPlayer()
if err != nil { if err != nil {
log.Println("Error while reading message:", err) log.Println("Error while reading message:", err)
// At the moment, we return when there is an error while reading a message. // At the moment, we return when there is an error while reading a message.
@ -63,12 +75,12 @@ func (game *Game) handle() {
game.currentTurnPlayer = game.players[0] game.currentTurnPlayer = game.players[0]
} }
err := WriteMessageToPlayer(&game.players[0], receivedMessage, messageType) err := game.getPlayer1().WriteMessageToPlayer(receivedMessage)
if err != nil { if err != nil {
log.Println("Error during message writing:", err) log.Println("Error during message writing:", err)
continue continue
} }
err = WriteMessageToPlayer(&game.players[1], receivedMessage, messageType) err = game.getPlayer2().WriteMessageToPlayer(receivedMessage)
if err != nil { if err != nil {
log.Println("Error during message writing:", err) log.Println("Error during message writing:", err)
continue continue
@ -87,15 +99,11 @@ func (game *Game) handle() {
func (game *Game) addPlayersToGame(players [2]Player) { 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()) log.Printf("Adding players %s and %s to new game", players[0].Uuid.String(), players[1].Uuid.String())
for _, player := range players { for i := range players {
player.InGame = true players[i].InGame = true
} }
game.players = players game.players = players
go game.handle() go game.handle()
} }
func removePlayersFromLobby(players [2]Player) {
panic("not yet implemented")
}

View File

@ -1,14 +1,19 @@
package server package server
import ( import (
"sync"
"github.com/google/uuid" "github.com/google/uuid"
) )
type Lobby map[uuid.UUID]Player type Lobby struct {
players map[uuid.UUID]*Player
mutex sync.Mutex
}
var lobbyInstance Lobby = nil var lobbyInstance *Lobby = nil
func GetLobby() Lobby { func GetLobby() *Lobby {
if lobbyInstance == nil { if lobbyInstance == nil {
lobbyInstance = newLobby() lobbyInstance = newLobby()
} }
@ -16,28 +21,40 @@ func GetLobby() Lobby {
return lobbyInstance return lobbyInstance
} }
func newLobby() Lobby { func newLobby() *Lobby {
lobby := make(map[uuid.UUID]Player, 0) return &Lobby{
return lobby players: make(map[uuid.UUID]*Player, 0),
}
} }
func (lobby Lobby) RegisterPlayer(player *Player) { func (l *Lobby) RegisterPlayer(player *Player) {
lobby[player.Uuid] = *player l.players[player.Uuid] = player
var players []Player var playersToBeAddedToGame []Player
for _, player := range lobby { for _, player := range l.players {
if !player.InGame { if !player.InGame {
players = append(players, player) playersToBeAddedToGame = append(playersToBeAddedToGame, *player)
} }
} }
if len(players) < 2 { if len(playersToBeAddedToGame) < 2 {
return return
} }
game := NewGame() game := NewGame()
game.addPlayersToGame([2]Player(playersToBeAddedToGame[:2]))
game.addPlayersToGame([2]Player(players[: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

@ -1,14 +1,19 @@
package server package server
import ( import (
"context"
"log"
"github.com/google/uuid" "github.com/google/uuid"
"nhooyr.io/websocket" "nhooyr.io/websocket"
) )
type Player struct { type Player struct {
Uuid uuid.UUID Uuid uuid.UUID
Conn *websocket.Conn Conn *websocket.Conn
InGame bool InGame bool
wsConnEstablished chan bool
context context.Context
} }
type PlayerInfo struct { type PlayerInfo struct {
@ -17,6 +22,28 @@ type PlayerInfo struct {
func NewPlayer(uuid uuid.UUID) *Player { func NewPlayer(uuid uuid.UUID) *Player {
return &Player{ return &Player{
Uuid: uuid, Uuid: uuid,
Conn: nil,
InGame: false,
wsConnEstablished: make(chan bool),
} }
} }
func (p *Player) SetConnection(ctx context.Context, conn websocket.Conn) {
p.Conn = &conn
p.context = ctx
p.wsConnEstablished <- true
}
func (p *Player) WriteMessageToPlayer(msg []byte) error {
log.Printf("Writing message: %s to player %d", string(msg), p.Uuid)
return p.Conn.Write(p.context, websocket.MessageText, msg)
}
func (p *Player) ReadMessageFromPlayer() (websocket.MessageType, []byte, error) {
msgType, msg, err := p.Conn.Read(p.context)
log.Printf("Reading message: %s (with messagetype %d) from player %d", string(msg), msgType, p.Uuid)
return msgType, msg, err
}

View File

@ -9,11 +9,3 @@ var AppPath = "/home/m/projects/programming/flutter_projects/mchess/build/web"
func PlayHandler(w http.ResponseWriter, r *http.Request) { func PlayHandler(w http.ResponseWriter, r *http.Request) {
} }
func WriteMessageToPlayer(player *Player, msg []byte, msgType int) error {
panic("Not implemented")
}
func ReadMessageFromPlayer(player *Player) (messageType int, p []byte, err error) {
panic("Not implemented")
}