package chess import ( "context" "encoding/json" "errors" "log" "mchess_server/api" "mchess_server/connection" "mchess_server/types" "github.com/google/uuid" gorillaws "github.com/gorilla/websocket" ) type Player struct { Uuid uuid.UUID Conn *connection.Connection color types.ChessColor disconnectCallback func(p *Player) } func NewPlayer(uuid uuid.UUID) *Player { player := &Player{ Uuid: uuid, Conn: connection.NewConnection( connection.WithContext(context.Background())), } return player } func (p Player) hasWebsocketConnection() bool { return p.Conn.HasWebsocketConnection() } func (p *Player) SetWebsocketConnection(ctx context.Context, ws *gorillaws.Conn) { p.Conn.SetWebsocketConnection(ws) p.Conn.SetForColor(p.color) } func (p *Player) SetWebsocketConnectionAndSendBoardState( ctx context.Context, ws *gorillaws.Conn, board *Board, ) { p.SetWebsocketConnection(ctx, ws) p.SendBoardState(board.getLastMove(), board.PGN(), board.colorToMove) } func (p *Player) SetColor(color types.ChessColor) { p.color = color p.Conn.SetForColor(p.color) } func (p *Player) GetColor() types.ChessColor { return p.color } func (p *Player) SetDisconnectCallback(cb func(*Player)) { // Todo: Fucking complicated p.Conn.SetDisconnectCallback(p.PlayerDisconnectedCallback) p.disconnectCallback = cb } func (p *Player) PlayerDisconnectedCallback() { p.disconnectCallback(p) } func (p *Player) IsInGame() bool { return p.hasWebsocketConnection() } func (p *Player) SendBoardState(move types.Move, boardPosition string, turnColor types.ChessColor) error { var pColor = p.GetColor() if p.GetColor() == "" { // we default to white if we do not know the color yet pColor = types.White } messageToSend, err := json.Marshal(api.WebsocketMessage{ Move: &move, Type: api.BoardStateMessage, TurnColor: &turnColor, PlayerColor: &pColor, Position: &boardPosition, }) if err != nil { log.Println("Error while marshalling: ", err) return err } err = p.writeMessage(messageToSend) if err != nil { log.Println("Error during message writing:", err) return err } return nil } func (p *Player) SendMoveAndPosition(move types.Move, boardPosition string) error { messageToSend, err := json.Marshal(api.WebsocketMessage{ Type: api.MoveMessage, Move: &move, Position: &boardPosition, }) if err != nil { log.Println("Error while marshalling: ", err) return err } err = p.writeMessage(messageToSend) if err != nil { log.Println("Error during message writing:", err) return err } return nil } func (p *Player) SendGameEnded(reason GameEndedReason) error { reasonToSend := reason.String() messageToSend, err := json.Marshal(api.WebsocketMessage{ Type: api.GameEnded, Reason: &reasonToSend, }) if err != nil { log.Println("Error while marshalling: ", err) return err } err = p.writeMessage(messageToSend) if err != nil { log.Println("Error during message writing:", err) return err } return nil } func (p *Player) writeMessage(msg []byte) error { return p.Conn.Write(msg) } func (p *Player) ReadMove() (types.Move, error) { receivedMessage, err := p.readMessage() if err != nil { return types.Move{}, err } var msg api.WebsocketMessage err = json.Unmarshal(receivedMessage, &msg) if err != nil { return types.Move{}, err } if !msg.IsValid() { return types.Move{}, errors.New("not a valid move") } return *msg.Move, nil } func (p *Player) readMessage() ([]byte, error) { msg, err := p.Conn.Read() log.Printf("Reading message from %s: %s", p.color.String(), string(msg)) return msg, err }