From 65689b903f8076c2b7a2f832e619816cab28f6c0 Mon Sep 17 00:00:00 2001 From: Ilia Denisov Date: Wed, 3 Jun 2026 00:49:07 +0200 Subject: [PATCH] Stage 7 (wip): wire remaining ops (backend REST, FBS, gateway transcode) + real UI transport backend: REST handlers for pass/exchange/resign/hint/evaluate/check_word/complaint/history/chat-list/nudge + new game.ListForAccount (my games) + seat display_name resolution pkg/fbs: GameActionRequest/ExchangeRequest/EvalRequest/EvalResult/CheckWordRequest/WordCheckResult/ComplaintRequest/HintResult/History/GameList/ChatList + SeatView.display_name; committed Go regenerated (flatc 23.5.26) gateway: 11 new transcode ops + backendclient methods + FB encoders ui: edge TS codegen (flatc --ts + protoc-gen-es, committed), FlatBuffers<->model codec, real connect-web transport (binary, bearer auth, Subscribe). prod bundle ~69KB gzip JS --- backend/internal/game/service.go | 7 + backend/internal/game/store.go | 44 ++ backend/internal/server/dto.go | 14 +- backend/internal/server/handlers.go | 11 + backend/internal/server/handlers_game.go | 321 +++++++++++++++ backend/internal/server/handlers_user.go | 18 +- gateway/internal/backendclient/api.go | 128 +++++- gateway/internal/transcode/encode.go | 105 ++++- gateway/internal/transcode/transcode.go | 169 ++++++++ pkg/fbs/scrabble.fbs | 70 +++- pkg/fbs/scrabblefb/ChatList.go | 75 ++++ pkg/fbs/scrabblefb/CheckWordRequest.go | 71 ++++ pkg/fbs/scrabblefb/ComplaintRequest.go | 82 ++++ pkg/fbs/scrabblefb/EvalRequest.go | 97 +++++ pkg/fbs/scrabblefb/EvalResult.go | 102 +++++ pkg/fbs/scrabblefb/ExchangeRequest.go | 83 ++++ pkg/fbs/scrabblefb/GameActionRequest.go | 60 +++ pkg/fbs/scrabblefb/GameList.go | 75 ++++ pkg/fbs/scrabblefb/HintResult.go | 80 ++++ pkg/fbs/scrabblefb/History.go | 86 ++++ pkg/fbs/scrabblefb/SeatView.go | 13 +- pkg/fbs/scrabblefb/WordCheckResult.go | 75 ++++ ui/buf.gen.yaml | 9 + ui/package.json | 8 + ui/pnpm-lock.yaml | 94 +++++ ui/src/gen/edge/v1/edge_pb.ts | 159 ++++++++ ui/src/gen/fbs/scrabble.ts | 3 + ui/src/gen/fbs/scrabblefb.ts | 36 ++ ui/src/gen/fbs/scrabblefb/ack.ts | 46 +++ ui/src/gen/fbs/scrabblefb/chat-list.ts | 66 +++ ui/src/gen/fbs/scrabblefb/chat-message.ts | 106 +++++ .../gen/fbs/scrabblefb/chat-post-request.ts | 60 +++ .../gen/fbs/scrabblefb/check-word-request.ts | 60 +++ .../gen/fbs/scrabblefb/complaint-request.ts | 72 ++++ .../gen/fbs/scrabblefb/email-login-request.ts | 60 +++ .../fbs/scrabblefb/email-request-request.ts | 48 +++ ui/src/gen/fbs/scrabblefb/enqueue-request.ts | 48 +++ ui/src/gen/fbs/scrabblefb/eval-request.ts | 90 ++++ ui/src/gen/fbs/scrabblefb/eval-result.ts | 85 ++++ ui/src/gen/fbs/scrabblefb/exchange-request.ts | 77 ++++ .../gen/fbs/scrabblefb/game-action-request.ts | 48 +++ ui/src/gen/fbs/scrabblefb/game-list.ts | 66 +++ ui/src/gen/fbs/scrabblefb/game-view.ts | 166 ++++++++ .../gen/fbs/scrabblefb/guest-login-request.ts | 48 +++ ui/src/gen/fbs/scrabblefb/hint-result.ts | 59 +++ ui/src/gen/fbs/scrabblefb/history.ts | 78 ++++ .../gen/fbs/scrabblefb/match-found-event.ts | 48 +++ ui/src/gen/fbs/scrabblefb/match-result.ts | 53 +++ ui/src/gen/fbs/scrabblefb/move-record.ts | 179 ++++++++ ui/src/gen/fbs/scrabblefb/move-result.ts | 54 +++ ui/src/gen/fbs/scrabblefb/nudge-event.ts | 60 +++ .../fbs/scrabblefb/opponent-moved-event.ts | 90 ++++ ui/src/gen/fbs/scrabblefb/profile.ts | 124 ++++++ ui/src/gen/fbs/scrabblefb/seat-view.ts | 100 +++++ ui/src/gen/fbs/scrabblefb/session.ts | 82 ++++ ui/src/gen/fbs/scrabblefb/state-request.ts | 48 +++ ui/src/gen/fbs/scrabblefb/state-view.ts | 108 +++++ .../gen/fbs/scrabblefb/submit-play-request.ts | 90 ++++ .../fbs/scrabblefb/telegram-login-request.ts | 48 +++ ui/src/gen/fbs/scrabblefb/tile-record.ts | 78 ++++ .../gen/fbs/scrabblefb/word-check-result.ts | 58 +++ ui/src/gen/fbs/scrabblefb/your-turn-event.ts | 58 +++ ui/src/lib/codec.ts | 384 ++++++++++++++++++ ui/src/lib/transport.ts | 163 ++++++-- 64 files changed, 5151 insertions(+), 52 deletions(-) create mode 100644 backend/internal/server/handlers_game.go create mode 100644 pkg/fbs/scrabblefb/ChatList.go create mode 100644 pkg/fbs/scrabblefb/CheckWordRequest.go create mode 100644 pkg/fbs/scrabblefb/ComplaintRequest.go create mode 100644 pkg/fbs/scrabblefb/EvalRequest.go create mode 100644 pkg/fbs/scrabblefb/EvalResult.go create mode 100644 pkg/fbs/scrabblefb/ExchangeRequest.go create mode 100644 pkg/fbs/scrabblefb/GameActionRequest.go create mode 100644 pkg/fbs/scrabblefb/GameList.go create mode 100644 pkg/fbs/scrabblefb/HintResult.go create mode 100644 pkg/fbs/scrabblefb/History.go create mode 100644 pkg/fbs/scrabblefb/WordCheckResult.go create mode 100644 ui/buf.gen.yaml create mode 100644 ui/src/gen/edge/v1/edge_pb.ts create mode 100644 ui/src/gen/fbs/scrabble.ts create mode 100644 ui/src/gen/fbs/scrabblefb.ts create mode 100644 ui/src/gen/fbs/scrabblefb/ack.ts create mode 100644 ui/src/gen/fbs/scrabblefb/chat-list.ts create mode 100644 ui/src/gen/fbs/scrabblefb/chat-message.ts create mode 100644 ui/src/gen/fbs/scrabblefb/chat-post-request.ts create mode 100644 ui/src/gen/fbs/scrabblefb/check-word-request.ts create mode 100644 ui/src/gen/fbs/scrabblefb/complaint-request.ts create mode 100644 ui/src/gen/fbs/scrabblefb/email-login-request.ts create mode 100644 ui/src/gen/fbs/scrabblefb/email-request-request.ts create mode 100644 ui/src/gen/fbs/scrabblefb/enqueue-request.ts create mode 100644 ui/src/gen/fbs/scrabblefb/eval-request.ts create mode 100644 ui/src/gen/fbs/scrabblefb/eval-result.ts create mode 100644 ui/src/gen/fbs/scrabblefb/exchange-request.ts create mode 100644 ui/src/gen/fbs/scrabblefb/game-action-request.ts create mode 100644 ui/src/gen/fbs/scrabblefb/game-list.ts create mode 100644 ui/src/gen/fbs/scrabblefb/game-view.ts create mode 100644 ui/src/gen/fbs/scrabblefb/guest-login-request.ts create mode 100644 ui/src/gen/fbs/scrabblefb/hint-result.ts create mode 100644 ui/src/gen/fbs/scrabblefb/history.ts create mode 100644 ui/src/gen/fbs/scrabblefb/match-found-event.ts create mode 100644 ui/src/gen/fbs/scrabblefb/match-result.ts create mode 100644 ui/src/gen/fbs/scrabblefb/move-record.ts create mode 100644 ui/src/gen/fbs/scrabblefb/move-result.ts create mode 100644 ui/src/gen/fbs/scrabblefb/nudge-event.ts create mode 100644 ui/src/gen/fbs/scrabblefb/opponent-moved-event.ts create mode 100644 ui/src/gen/fbs/scrabblefb/profile.ts create mode 100644 ui/src/gen/fbs/scrabblefb/seat-view.ts create mode 100644 ui/src/gen/fbs/scrabblefb/session.ts create mode 100644 ui/src/gen/fbs/scrabblefb/state-request.ts create mode 100644 ui/src/gen/fbs/scrabblefb/state-view.ts create mode 100644 ui/src/gen/fbs/scrabblefb/submit-play-request.ts create mode 100644 ui/src/gen/fbs/scrabblefb/telegram-login-request.ts create mode 100644 ui/src/gen/fbs/scrabblefb/tile-record.ts create mode 100644 ui/src/gen/fbs/scrabblefb/word-check-result.ts create mode 100644 ui/src/gen/fbs/scrabblefb/your-turn-event.ts create mode 100644 ui/src/lib/codec.ts diff --git a/backend/internal/game/service.go b/backend/internal/game/service.go index 62fd3a4..9d0793d 100644 --- a/backend/internal/game/service.go +++ b/backend/internal/game/service.go @@ -566,6 +566,13 @@ func (svc *Service) Participants(ctx context.Context, gameID uuid.UUID) ([]uuid. return seats, g.ToMove, g.Status, nil } +// ListForAccount returns every game the account is seated in, newest first, for the +// lobby's active/finished lists. The live position is not loaded — the summaries come +// straight from the durable rows. +func (svc *Service) ListForAccount(ctx context.Context, accountID uuid.UUID) ([]Game, error) { + return svc.store.ListGamesForAccount(ctx, accountID) +} + // History returns a game's full, dictionary-independent move journal. func (svc *Service) History(ctx context.Context, gameID uuid.UUID) (HistoryView, error) { g, err := svc.store.GetGame(ctx, gameID) diff --git a/backend/internal/game/store.go b/backend/internal/game/store.go index 48687de..7969f2e 100644 --- a/backend/internal/game/store.go +++ b/backend/internal/game/store.go @@ -135,6 +135,50 @@ func (s *Store) GetGame(ctx context.Context, id uuid.UUID) (Game, error) { return projectGame(grow, srows) } +// ListGamesForAccount loads every game the account is seated in (active and +// finished), newest first, each joined with its ordered seats. It backs the lobby's +// "my games" lists. +func (s *Store) ListGamesForAccount(ctx context.Context, accountID uuid.UUID) ([]Game, error) { + gstmt := postgres.SELECT(table.Games.AllColumns). + FROM(table.Games.INNER_JOIN(table.GamePlayers, table.GamePlayers.GameID.EQ(table.Games.GameID))). + WHERE(table.GamePlayers.AccountID.EQ(postgres.UUID(accountID))). + ORDER_BY(table.Games.UpdatedAt.DESC()) + var grows []model.Games + if err := gstmt.QueryContext(ctx, s.db, &grows); err != nil { + return nil, fmt.Errorf("game: list for account: %w", err) + } + if len(grows) == 0 { + return nil, nil + } + + ids := make([]postgres.Expression, len(grows)) + for i, g := range grows { + ids[i] = postgres.UUID(g.GameID) + } + sstmt := postgres.SELECT(table.GamePlayers.AllColumns). + FROM(table.GamePlayers). + WHERE(table.GamePlayers.GameID.IN(ids...)). + ORDER_BY(table.GamePlayers.GameID.ASC(), table.GamePlayers.Seat.ASC()) + var srows []model.GamePlayers + if err := sstmt.QueryContext(ctx, s.db, &srows); err != nil { + return nil, fmt.Errorf("game: list seats for account: %w", err) + } + byGame := make(map[uuid.UUID][]model.GamePlayers, len(grows)) + for _, r := range srows { + byGame[r.GameID] = append(byGame[r.GameID], r) + } + + out := make([]Game, 0, len(grows)) + for _, g := range grows { + pg, err := projectGame(g, byGame[g.GameID]) + if err != nil { + return nil, err + } + out = append(out, pg) + } + return out, nil +} + // GetJournal loads the ordered, decoded move journal for a game. func (s *Store) GetJournal(ctx context.Context, id uuid.UUID) ([]HistoryMove, error) { stmt := postgres.SELECT(table.GameMoves.AllColumns). diff --git a/backend/internal/server/dto.go b/backend/internal/server/dto.go index 2fc4990..7e39b4f 100644 --- a/backend/internal/server/dto.go +++ b/backend/internal/server/dto.go @@ -66,13 +66,15 @@ type moveRecordDTO struct { Total int `json:"total"` } -// seatDTO is one seat's public standing. +// seatDTO is one seat's public standing. DisplayName is resolved from the account +// store by the handler (the game domain keys seats by account id only). type seatDTO struct { - Seat int `json:"seat"` - AccountID string `json:"account_id"` - Score int `json:"score"` - HintsUsed int `json:"hints_used"` - IsWinner bool `json:"is_winner"` + Seat int `json:"seat"` + AccountID string `json:"account_id"` + DisplayName string `json:"display_name"` + Score int `json:"score"` + HintsUsed int `json:"hints_used"` + IsWinner bool `json:"is_winner"` } // gameDTO is the shared game summary. diff --git a/backend/internal/server/handlers.go b/backend/internal/server/handlers.go index de3a62d..dc822aa 100644 --- a/backend/internal/server/handlers.go +++ b/backend/internal/server/handlers.go @@ -37,8 +37,17 @@ func (s *Server) registerRoutes() { u.GET("/profile", s.handleProfile) } if s.games != nil { + u.GET("/games", s.handleListGames) u.POST("/games/:id/play", s.handleSubmitPlay) u.GET("/games/:id/state", s.handleGameState) + u.POST("/games/:id/pass", s.handlePass) + u.POST("/games/:id/exchange", s.handleExchange) + u.POST("/games/:id/resign", s.handleResign) + u.POST("/games/:id/hint", s.handleHint) + u.POST("/games/:id/evaluate", s.handleEvaluate) + u.GET("/games/:id/check_word", s.handleCheckWord) + u.POST("/games/:id/complaint", s.handleComplaint) + u.GET("/games/:id/history", s.handleHistory) } if s.matchmaker != nil { u.POST("/lobby/enqueue", s.handleEnqueue) @@ -46,6 +55,8 @@ func (s *Server) registerRoutes() { } if s.social != nil { u.POST("/games/:id/chat", s.handleChatPost) + u.GET("/games/:id/chat", s.handleChatList) + u.POST("/games/:id/nudge", s.handleNudge) } s.admin.GET("/ping", s.handleAdminPing) } diff --git a/backend/internal/server/handlers_game.go b/backend/internal/server/handlers_game.go new file mode 100644 index 0000000..4a5ad11 --- /dev/null +++ b/backend/internal/server/handlers_game.go @@ -0,0 +1,321 @@ +package server + +import ( + "context" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" + + "scrabble/backend/internal/engine" + "scrabble/backend/internal/game" +) + +// The handlers below extend the Stage 6 vertical slice with the remaining game and +// chat operations the UI needs (PLAN.md Stage 7). They follow the same pattern as +// handlers_user.go: X-User-ID identity, the domain service call, a JSON DTO mapped +// from the result. + +// hintResultDTO is the top-ranked move plus the remaining hint budget. +type hintResultDTO struct { + Move moveRecordDTO `json:"move"` + HintsRemaining int `json:"hints_remaining"` +} + +// evalResultDTO is an unlimited move preview: legality, score and the words formed. +type evalResultDTO struct { + Legal bool `json:"legal"` + Score int `json:"score"` + Words []string `json:"words"` +} + +// wordCheckDTO is the result of the unlimited dictionary lookup tool. +type wordCheckDTO struct { + Word string `json:"word"` + Legal bool `json:"legal"` +} + +// historyDTO is a game's decoded move journal, the source for client board replay. +type historyDTO struct { + GameID string `json:"game_id"` + Moves []moveRecordDTO `json:"moves"` +} + +// gameListDTO is the caller's games (active and finished) for the lobby. +type gameListDTO struct { + Games []gameDTO `json:"games"` +} + +// chatListDTO is a game's chat history. +type chatListDTO struct { + Messages []chatDTO `json:"messages"` +} + +// exchangeRequest swaps the given rack tiles back into the bag. +type exchangeRequest struct { + Tiles []string `json:"tiles"` +} + +// complaintRequest disputes a word-check result. +type complaintRequest struct { + Word string `json:"word"` + Note string `json:"note"` +} + +// fillSeatNames resolves each seat's display name from the account store, memoising +// across seats and games within one request. +func (s *Server) fillSeatNames(ctx context.Context, g *gameDTO, memo map[string]string) { + for i := range g.Seats { + id := g.Seats[i].AccountID + name, ok := memo[id] + if !ok { + if uid, err := uuid.Parse(id); err == nil { + if acc, err := s.accounts.GetByID(ctx, uid); err == nil { + name = acc.DisplayName + } + } + memo[id] = name + } + g.Seats[i].DisplayName = name + } +} + +// moveRecordDTOFromHistory projects a journal move into the shared move DTO. +func moveRecordDTOFromHistory(m game.HistoryMove) moveRecordDTO { + tiles := make([]tileDTO, 0, len(m.Tiles)) + for _, t := range m.Tiles { + tiles = append(tiles, tileDTO{Row: t.Row, Col: t.Col, Letter: t.Letter, Blank: t.Blank}) + } + return moveRecordDTO{ + Player: m.Seat, + Action: m.Action, + Dir: m.Dir, + MainRow: m.MainRow, + MainCol: m.MainCol, + Tiles: tiles, + Words: m.Words, + Count: len(m.Words), + Score: m.Score, + Total: m.RunningTotal, + } +} + +// handlePass forfeits the player's turn. +func (s *Server) handlePass(c *gin.Context) { + uid, gameID, ok := s.userGame(c) + if !ok { + return + } + res, err := s.games.Pass(c.Request.Context(), gameID, uid) + if err != nil { + s.abortErr(c, err) + return + } + s.writeMoveResult(c, res) +} + +// handleExchange swaps the chosen rack tiles back into the bag. +func (s *Server) handleExchange(c *gin.Context) { + uid, gameID, ok := s.userGame(c) + if !ok { + return + } + var req exchangeRequest + if err := c.ShouldBindJSON(&req); err != nil { + abortBadRequest(c, "invalid request body") + return + } + res, err := s.games.Exchange(c.Request.Context(), gameID, uid, req.Tiles) + if err != nil { + s.abortErr(c, err) + return + } + s.writeMoveResult(c, res) +} + +// handleResign resigns the player from the game. +func (s *Server) handleResign(c *gin.Context) { + uid, gameID, ok := s.userGame(c) + if !ok { + return + } + res, err := s.games.Resign(c.Request.Context(), gameID, uid) + if err != nil { + s.abortErr(c, err) + return + } + s.writeMoveResult(c, res) +} + +// handleHint reveals the top-ranked move and spends a hint. +func (s *Server) handleHint(c *gin.Context) { + uid, gameID, ok := s.userGame(c) + if !ok { + return + } + h, err := s.games.Hint(c.Request.Context(), gameID, uid) + if err != nil { + s.abortErr(c, err) + return + } + c.JSON(http.StatusOK, hintResultDTO{ + Move: moveRecordDTOFrom(h.Move), + HintsRemaining: h.HintsRemaining, + }) +} + +// handleEvaluate previews a tentative play's legality and score. +func (s *Server) handleEvaluate(c *gin.Context) { + uid, gameID, ok := s.userGame(c) + if !ok { + return + } + var req submitPlayRequest + if err := c.ShouldBindJSON(&req); err != nil { + abortBadRequest(c, "invalid request body") + return + } + dir, ok := parseDirection(req.Dir) + if !ok { + abortBadRequest(c, "dir must be H or V") + return + } + tiles := make([]engine.TileRecord, 0, len(req.Tiles)) + for _, t := range req.Tiles { + tiles = append(tiles, engine.TileRecord{Row: t.Row, Col: t.Col, Letter: t.Letter, Blank: t.Blank}) + } + ev, err := s.games.EvaluatePlay(c.Request.Context(), gameID, uid, dir, tiles) + if err != nil { + s.abortErr(c, err) + return + } + c.JSON(http.StatusOK, evalResultDTO{Legal: ev.Valid, Score: ev.Score, Words: ev.Words}) +} + +// handleCheckWord looks a word up in the game's pinned dictionary. +func (s *Server) handleCheckWord(c *gin.Context) { + _, gameID, ok := s.userGame(c) + if !ok { + return + } + word := c.Query("word") + legal, err := s.games.CheckWord(c.Request.Context(), gameID, word) + if err != nil { + s.abortErr(c, err) + return + } + c.JSON(http.StatusOK, wordCheckDTO{Word: word, Legal: legal}) +} + +// handleComplaint files a word-check complaint into the admin review queue. +func (s *Server) handleComplaint(c *gin.Context) { + uid, gameID, ok := s.userGame(c) + if !ok { + return + } + var req complaintRequest + if err := c.ShouldBindJSON(&req); err != nil { + abortBadRequest(c, "invalid request body") + return + } + if _, err := s.games.FileComplaint(c.Request.Context(), gameID, uid, req.Word, req.Note); err != nil { + s.abortErr(c, err) + return + } + c.JSON(http.StatusOK, okResponse{OK: true}) +} + +// handleHistory returns a game's decoded move journal for board replay / history. +func (s *Server) handleHistory(c *gin.Context) { + _, gameID, ok := s.userGame(c) + if !ok { + return + } + view, err := s.games.History(c.Request.Context(), gameID) + if err != nil { + s.abortErr(c, err) + return + } + moves := make([]moveRecordDTO, 0, len(view.Moves)) + for _, m := range view.Moves { + moves = append(moves, moveRecordDTOFromHistory(m)) + } + c.JSON(http.StatusOK, historyDTO{GameID: gameID.String(), Moves: moves}) +} + +// handleListGames returns the caller's active and finished games for the lobby. +func (s *Server) handleListGames(c *gin.Context) { + uid, ok := userID(c) + if !ok { + abortBadRequest(c, "missing identity") + return + } + games, err := s.games.ListForAccount(c.Request.Context(), uid) + if err != nil { + s.abortErr(c, err) + return + } + memo := map[string]string{} + out := make([]gameDTO, 0, len(games)) + for _, g := range games { + dto := gameDTOFromGame(g) + s.fillSeatNames(c.Request.Context(), &dto, memo) + out = append(out, dto) + } + c.JSON(http.StatusOK, gameListDTO{Games: out}) +} + +// handleChatList returns a game's chat history for the viewer. +func (s *Server) handleChatList(c *gin.Context) { + uid, gameID, ok := s.userGame(c) + if !ok { + return + } + msgs, err := s.social.Messages(c.Request.Context(), gameID, uid) + if err != nil { + s.abortErr(c, err) + return + } + out := make([]chatDTO, 0, len(msgs)) + for _, m := range msgs { + out = append(out, chatDTOFrom(m)) + } + c.JSON(http.StatusOK, chatListDTO{Messages: out}) +} + +// handleNudge posts a nudge to the player whose turn is awaited. +func (s *Server) handleNudge(c *gin.Context) { + uid, gameID, ok := s.userGame(c) + if !ok { + return + } + msg, err := s.social.Nudge(c.Request.Context(), gameID, uid) + if err != nil { + s.abortErr(c, err) + return + } + c.JSON(http.StatusOK, chatDTOFrom(msg)) +} + +// userGame reads the authenticated account and the :id game param, aborting with the +// right status when either is missing. ok is false when the request was aborted. +func (s *Server) userGame(c *gin.Context) (uuid.UUID, uuid.UUID, bool) { + uid, ok := userID(c) + if !ok { + abortBadRequest(c, "missing identity") + return uuid.UUID{}, uuid.UUID{}, false + } + gameID, ok := gameIDParam(c) + if !ok { + abortBadRequest(c, "invalid game id") + return uuid.UUID{}, uuid.UUID{}, false + } + return uid, gameID, true +} + +// writeMoveResult emits a committed move with seat display names filled in. +func (s *Server) writeMoveResult(c *gin.Context, res game.MoveResult) { + dto := moveResultDTOFrom(res) + s.fillSeatNames(c.Request.Context(), &dto.Game, map[string]string{}) + c.JSON(http.StatusOK, dto) +} diff --git a/backend/internal/server/handlers_user.go b/backend/internal/server/handlers_user.go index 6f297d6..60d6a1e 100644 --- a/backend/internal/server/handlers_user.go +++ b/backend/internal/server/handlers_user.go @@ -68,7 +68,7 @@ func (s *Server) handleSubmitPlay(c *gin.Context) { s.abortErr(c, err) return } - c.JSON(http.StatusOK, moveResultDTOFrom(res)) + s.writeMoveResult(c, res) } // handleGameState returns the player's view of a game. @@ -88,7 +88,9 @@ func (s *Server) handleGameState(c *gin.Context) { s.abortErr(c, err) return } - c.JSON(http.StatusOK, stateDTOFrom(view)) + dto := stateDTOFrom(view) + s.fillSeatNames(c.Request.Context(), &dto.Game, map[string]string{}) + c.JSON(http.StatusOK, dto) } // enqueueRequest joins the per-variant auto-match pool. @@ -118,7 +120,11 @@ func (s *Server) handleEnqueue(c *gin.Context) { s.abortErr(c, err) return } - c.JSON(http.StatusOK, matchDTOFrom(res)) + dto := matchDTOFrom(res) + if dto.Game != nil { + s.fillSeatNames(c.Request.Context(), dto.Game, map[string]string{}) + } + c.JSON(http.StatusOK, dto) } // handlePoll reports whether the caller has been paired since queueing. @@ -133,7 +139,11 @@ func (s *Server) handlePoll(c *gin.Context) { s.abortErr(c, err) return } - c.JSON(http.StatusOK, matchDTOFrom(res)) + dto := matchDTOFrom(res) + if dto.Game != nil { + s.fillSeatNames(c.Request.Context(), dto.Game, map[string]string{}) + } + c.JSON(http.StatusOK, dto) } // chatPostRequest posts a per-game chat message. diff --git a/gateway/internal/backendclient/api.go b/gateway/internal/backendclient/api.go index 7554296..5c2afad 100644 --- a/gateway/internal/backendclient/api.go +++ b/gateway/internal/backendclient/api.go @@ -54,11 +54,12 @@ type MoveRecordResp struct { // SeatResp is one seat's public standing. type SeatResp struct { - Seat int `json:"seat"` - AccountID string `json:"account_id"` - Score int `json:"score"` - HintsUsed int `json:"hints_used"` - IsWinner bool `json:"is_winner"` + Seat int `json:"seat"` + AccountID string `json:"account_id"` + DisplayName string `json:"display_name"` + Score int `json:"score"` + HintsUsed int `json:"hints_used"` + IsWinner bool `json:"is_winner"` } // GameResp is the shared game summary. @@ -189,3 +190,120 @@ func (c *Client) ChatPost(ctx context.Context, userID, gameID, body, clientIP st map[string]string{"body": body}, &out) return out, err } + +// HintResultResp is the top-ranked move plus the remaining hint budget. +type HintResultResp struct { + Move MoveRecordResp `json:"move"` + HintsRemaining int `json:"hints_remaining"` +} + +// EvalResultResp is an unlimited move preview. +type EvalResultResp struct { + Legal bool `json:"legal"` + Score int `json:"score"` + Words []string `json:"words"` +} + +// WordCheckResp is a dictionary lookup outcome. +type WordCheckResp struct { + Word string `json:"word"` + Legal bool `json:"legal"` +} + +// HistoryResp is a game's decoded move journal. +type HistoryResp struct { + GameID string `json:"game_id"` + Moves []MoveRecordResp `json:"moves"` +} + +// GameListResp is the caller's games for the lobby. +type GameListResp struct { + Games []GameResp `json:"games"` +} + +// ChatListResp is a game's chat history. +type ChatListResp struct { + Messages []ChatResp `json:"messages"` +} + +func (c *Client) gamePath(gameID, suffix string) string { + return "/api/v1/user/games/" + url.PathEscape(gameID) + suffix +} + +// Pass forfeits the player's turn. +func (c *Client) Pass(ctx context.Context, userID, gameID string) (MoveResultResp, error) { + var out MoveResultResp + err := c.do(ctx, http.MethodPost, c.gamePath(gameID, "/pass"), userID, "", struct{}{}, &out) + return out, err +} + +// Exchange swaps the chosen rack tiles back into the bag. +func (c *Client) Exchange(ctx context.Context, userID, gameID string, tiles []string) (MoveResultResp, error) { + var out MoveResultResp + err := c.do(ctx, http.MethodPost, c.gamePath(gameID, "/exchange"), userID, "", + map[string]any{"tiles": tiles}, &out) + return out, err +} + +// Resign resigns the player from the game. +func (c *Client) Resign(ctx context.Context, userID, gameID string) (MoveResultResp, error) { + var out MoveResultResp + err := c.do(ctx, http.MethodPost, c.gamePath(gameID, "/resign"), userID, "", struct{}{}, &out) + return out, err +} + +// Hint reveals the top-ranked move and spends a hint. +func (c *Client) Hint(ctx context.Context, userID, gameID string) (HintResultResp, error) { + var out HintResultResp + err := c.do(ctx, http.MethodPost, c.gamePath(gameID, "/hint"), userID, "", struct{}{}, &out) + return out, err +} + +// Evaluate previews a tentative play's legality and score. +func (c *Client) Evaluate(ctx context.Context, userID, gameID, dir string, tiles []TileJSON) (EvalResultResp, error) { + var out EvalResultResp + err := c.do(ctx, http.MethodPost, c.gamePath(gameID, "/evaluate"), userID, "", + map[string]any{"dir": dir, "tiles": tiles}, &out) + return out, err +} + +// CheckWord looks a word up in the game's pinned dictionary. +func (c *Client) CheckWord(ctx context.Context, userID, gameID, word string) (WordCheckResp, error) { + var out WordCheckResp + err := c.do(ctx, http.MethodGet, c.gamePath(gameID, "/check_word")+"?word="+url.QueryEscape(word), userID, "", nil, &out) + return out, err +} + +// Complaint disputes a word-check result. +func (c *Client) Complaint(ctx context.Context, userID, gameID, word, note string) error { + return c.do(ctx, http.MethodPost, c.gamePath(gameID, "/complaint"), userID, "", + map[string]string{"word": word, "note": note}, nil) +} + +// History returns a game's decoded move journal. +func (c *Client) History(ctx context.Context, userID, gameID string) (HistoryResp, error) { + var out HistoryResp + err := c.do(ctx, http.MethodGet, c.gamePath(gameID, "/history"), userID, "", nil, &out) + return out, err +} + +// ChatList returns a game's chat history. +func (c *Client) ChatList(ctx context.Context, userID, gameID string) (ChatListResp, error) { + var out ChatListResp + err := c.do(ctx, http.MethodGet, c.gamePath(gameID, "/chat"), userID, "", nil, &out) + return out, err +} + +// Nudge posts a nudge to the player whose turn is awaited. +func (c *Client) Nudge(ctx context.Context, userID, gameID string) (ChatResp, error) { + var out ChatResp + err := c.do(ctx, http.MethodPost, c.gamePath(gameID, "/nudge"), userID, "", struct{}{}, &out) + return out, err +} + +// GamesList returns the caller's active and finished games. +func (c *Client) GamesList(ctx context.Context, userID string) (GameListResp, error) { + var out GameListResp + err := c.do(ctx, http.MethodGet, "/api/v1/user/games", userID, "", nil, &out) + return out, err +} diff --git a/gateway/internal/transcode/encode.go b/gateway/internal/transcode/encode.go index 08b529c..12fa03d 100644 --- a/gateway/internal/transcode/encode.go +++ b/gateway/internal/transcode/encode.go @@ -100,9 +100,8 @@ func encodeMatch(m backendclient.MatchResp) []byte { return b.FinishedBytes() } -// encodeChat builds a ChatMessage payload. -func encodeChat(c backendclient.ChatResp) []byte { - b := flatbuffers.NewBuilder(192) +// buildChatMessage builds a ChatMessage table and returns its offset. +func buildChatMessage(b *flatbuffers.Builder, c backendclient.ChatResp) flatbuffers.UOffsetT { id := b.CreateString(c.ID) gid := b.CreateString(c.GameID) sid := b.CreateString(c.SenderID) @@ -115,7 +114,103 @@ func encodeChat(c backendclient.ChatResp) []byte { fb.ChatMessageAddKind(b, kind) fb.ChatMessageAddBody(b, body) fb.ChatMessageAddCreatedAtUnix(b, c.CreatedAtUnix) - b.Finish(fb.ChatMessageEnd(b)) + return fb.ChatMessageEnd(b) +} + +// encodeChat builds a ChatMessage payload. +func encodeChat(c backendclient.ChatResp) []byte { + b := flatbuffers.NewBuilder(192) + b.Finish(buildChatMessage(b, c)) + return b.FinishedBytes() +} + +// encodeHintResult builds a HintResult payload. +func encodeHintResult(r backendclient.HintResultResp) []byte { + b := flatbuffers.NewBuilder(512) + move := buildMoveRecord(b, r.Move) + fb.HintResultStart(b) + fb.HintResultAddMove(b, move) + fb.HintResultAddHintsRemaining(b, int32(r.HintsRemaining)) + b.Finish(fb.HintResultEnd(b)) + return b.FinishedBytes() +} + +// encodeEvalResult builds an EvalResult payload. +func encodeEvalResult(r backendclient.EvalResultResp) []byte { + b := flatbuffers.NewBuilder(256) + words := buildStringVector(b, r.Words, fb.EvalResultStartWordsVector) + fb.EvalResultStart(b) + fb.EvalResultAddLegal(b, r.Legal) + fb.EvalResultAddScore(b, int32(r.Score)) + fb.EvalResultAddWords(b, words) + b.Finish(fb.EvalResultEnd(b)) + return b.FinishedBytes() +} + +// encodeWordCheck builds a WordCheckResult payload. +func encodeWordCheck(r backendclient.WordCheckResp) []byte { + b := flatbuffers.NewBuilder(64) + word := b.CreateString(r.Word) + fb.WordCheckResultStart(b) + fb.WordCheckResultAddWord(b, word) + fb.WordCheckResultAddLegal(b, r.Legal) + b.Finish(fb.WordCheckResultEnd(b)) + return b.FinishedBytes() +} + +// encodeHistory builds a History payload (the decoded move journal). +func encodeHistory(r backendclient.HistoryResp) []byte { + b := flatbuffers.NewBuilder(1024) + moveOffs := make([]flatbuffers.UOffsetT, len(r.Moves)) + for i, m := range r.Moves { + moveOffs[i] = buildMoveRecord(b, m) + } + fb.HistoryStartMovesVector(b, len(moveOffs)) + for i := len(moveOffs) - 1; i >= 0; i-- { + b.PrependUOffsetT(moveOffs[i]) + } + moves := b.EndVector(len(moveOffs)) + gid := b.CreateString(r.GameID) + fb.HistoryStart(b) + fb.HistoryAddGameId(b, gid) + fb.HistoryAddMoves(b, moves) + b.Finish(fb.HistoryEnd(b)) + return b.FinishedBytes() +} + +// encodeGameList builds a GameList payload (the caller's games). +func encodeGameList(r backendclient.GameListResp) []byte { + b := flatbuffers.NewBuilder(1024) + gameOffs := make([]flatbuffers.UOffsetT, len(r.Games)) + for i, g := range r.Games { + gameOffs[i] = buildGameView(b, g) + } + fb.GameListStartGamesVector(b, len(gameOffs)) + for i := len(gameOffs) - 1; i >= 0; i-- { + b.PrependUOffsetT(gameOffs[i]) + } + games := b.EndVector(len(gameOffs)) + fb.GameListStart(b) + fb.GameListAddGames(b, games) + b.Finish(fb.GameListEnd(b)) + return b.FinishedBytes() +} + +// encodeChatList builds a ChatList payload (a game's chat history). +func encodeChatList(r backendclient.ChatListResp) []byte { + b := flatbuffers.NewBuilder(512) + msgOffs := make([]flatbuffers.UOffsetT, len(r.Messages)) + for i, m := range r.Messages { + msgOffs[i] = buildChatMessage(b, m) + } + fb.ChatListStartMessagesVector(b, len(msgOffs)) + for i := len(msgOffs) - 1; i >= 0; i-- { + b.PrependUOffsetT(msgOffs[i]) + } + msgs := b.EndVector(len(msgOffs)) + fb.ChatListStart(b) + fb.ChatListAddMessages(b, msgs) + b.Finish(fb.ChatListEnd(b)) return b.FinishedBytes() } @@ -124,12 +219,14 @@ func buildGameView(b *flatbuffers.Builder, g backendclient.GameResp) flatbuffers seatOffs := make([]flatbuffers.UOffsetT, len(g.Seats)) for i, s := range g.Seats { aid := b.CreateString(s.AccountID) + dname := b.CreateString(s.DisplayName) fb.SeatViewStart(b) fb.SeatViewAddSeat(b, int32(s.Seat)) fb.SeatViewAddAccountId(b, aid) fb.SeatViewAddScore(b, int32(s.Score)) fb.SeatViewAddHintsUsed(b, int32(s.HintsUsed)) fb.SeatViewAddIsWinner(b, s.IsWinner) + fb.SeatViewAddDisplayName(b, dname) seatOffs[i] = fb.SeatViewEnd(b) } fb.GameViewStartSeatsVector(b, len(seatOffs)) diff --git a/gateway/internal/transcode/transcode.go b/gateway/internal/transcode/transcode.go index e6910cd..a6bdb9a 100644 --- a/gateway/internal/transcode/transcode.go +++ b/gateway/internal/transcode/transcode.go @@ -26,6 +26,17 @@ const ( MsgLobbyEnqueue = "lobby.enqueue" MsgLobbyPoll = "lobby.poll" MsgChatPost = "chat.post" + MsgGamesList = "games.list" + MsgGamePass = "game.pass" + MsgGameExchange = "game.exchange" + MsgGameResign = "game.resign" + MsgGameHint = "game.hint" + MsgGameEvaluate = "game.evaluate" + MsgGameCheckWord = "game.check_word" + MsgGameComplaint = "game.complaint" + MsgGameHistory = "game.history" + MsgChatList = "chat.list" + MsgChatNudge = "chat.nudge" ) // Request is one decoded Execute call. @@ -69,6 +80,17 @@ func NewRegistry(backend *backendclient.Client, tg auth.TelegramValidator) *Regi r.ops[MsgLobbyEnqueue] = Op{Handler: enqueueHandler(backend), Auth: true} r.ops[MsgLobbyPoll] = Op{Handler: pollHandler(backend), Auth: true} r.ops[MsgChatPost] = Op{Handler: chatPostHandler(backend), Auth: true} + r.ops[MsgGamesList] = Op{Handler: gamesListHandler(backend), Auth: true} + r.ops[MsgGamePass] = Op{Handler: passHandler(backend), Auth: true} + r.ops[MsgGameExchange] = Op{Handler: exchangeHandler(backend), Auth: true} + r.ops[MsgGameResign] = Op{Handler: resignHandler(backend), Auth: true} + r.ops[MsgGameHint] = Op{Handler: hintHandler(backend), Auth: true} + r.ops[MsgGameEvaluate] = Op{Handler: evaluateHandler(backend), Auth: true} + r.ops[MsgGameCheckWord] = Op{Handler: checkWordHandler(backend), Auth: true} + r.ops[MsgGameComplaint] = Op{Handler: complaintHandler(backend), Auth: true} + r.ops[MsgGameHistory] = Op{Handler: historyHandler(backend), Auth: true} + r.ops[MsgChatList] = Op{Handler: chatListHandler(backend), Auth: true} + r.ops[MsgChatNudge] = Op{Handler: nudgeHandler(backend), Auth: true} return r } @@ -219,3 +241,150 @@ func decodeTiles(in *fb.SubmitPlayRequest) []backendclient.TileJSON { } return tiles } + +// decodeEvalTiles reads the tentative tiles from an EvalRequest. +func decodeEvalTiles(in *fb.EvalRequest) []backendclient.TileJSON { + n := in.TilesLength() + tiles := make([]backendclient.TileJSON, 0, n) + var t fb.TileRecord + for i := 0; i < n; i++ { + if in.Tiles(&t, i) { + tiles = append(tiles, backendclient.TileJSON{ + Row: int(t.Row()), + Col: int(t.Col()), + Letter: string(t.Letter()), + Blank: t.Blank(), + }) + } + } + return tiles +} + +// decodeStringVector reads the exchange tiles from an ExchangeRequest. +func decodeStringVector(in *fb.ExchangeRequest) []string { + n := in.TilesLength() + out := make([]string, 0, n) + for i := 0; i < n; i++ { + out = append(out, string(in.Tiles(i))) + } + return out +} + +func gamesListHandler(backend *backendclient.Client) Handler { + return func(ctx context.Context, req Request) ([]byte, error) { + res, err := backend.GamesList(ctx, req.UserID) + if err != nil { + return nil, err + } + return encodeGameList(res), nil + } +} + +func passHandler(backend *backendclient.Client) Handler { + return func(ctx context.Context, req Request) ([]byte, error) { + in := fb.GetRootAsGameActionRequest(req.Payload, 0) + res, err := backend.Pass(ctx, req.UserID, string(in.GameId())) + if err != nil { + return nil, err + } + return encodeMoveResult(res), nil + } +} + +func resignHandler(backend *backendclient.Client) Handler { + return func(ctx context.Context, req Request) ([]byte, error) { + in := fb.GetRootAsGameActionRequest(req.Payload, 0) + res, err := backend.Resign(ctx, req.UserID, string(in.GameId())) + if err != nil { + return nil, err + } + return encodeMoveResult(res), nil + } +} + +func exchangeHandler(backend *backendclient.Client) Handler { + return func(ctx context.Context, req Request) ([]byte, error) { + in := fb.GetRootAsExchangeRequest(req.Payload, 0) + res, err := backend.Exchange(ctx, req.UserID, string(in.GameId()), decodeStringVector(in)) + if err != nil { + return nil, err + } + return encodeMoveResult(res), nil + } +} + +func hintHandler(backend *backendclient.Client) Handler { + return func(ctx context.Context, req Request) ([]byte, error) { + in := fb.GetRootAsGameActionRequest(req.Payload, 0) + res, err := backend.Hint(ctx, req.UserID, string(in.GameId())) + if err != nil { + return nil, err + } + return encodeHintResult(res), nil + } +} + +func evaluateHandler(backend *backendclient.Client) Handler { + return func(ctx context.Context, req Request) ([]byte, error) { + in := fb.GetRootAsEvalRequest(req.Payload, 0) + res, err := backend.Evaluate(ctx, req.UserID, string(in.GameId()), string(in.Dir()), decodeEvalTiles(in)) + if err != nil { + return nil, err + } + return encodeEvalResult(res), nil + } +} + +func checkWordHandler(backend *backendclient.Client) Handler { + return func(ctx context.Context, req Request) ([]byte, error) { + in := fb.GetRootAsCheckWordRequest(req.Payload, 0) + res, err := backend.CheckWord(ctx, req.UserID, string(in.GameId()), string(in.Word())) + if err != nil { + return nil, err + } + return encodeWordCheck(res), nil + } +} + +func complaintHandler(backend *backendclient.Client) Handler { + return func(ctx context.Context, req Request) ([]byte, error) { + in := fb.GetRootAsComplaintRequest(req.Payload, 0) + if err := backend.Complaint(ctx, req.UserID, string(in.GameId()), string(in.Word()), string(in.Note())); err != nil { + return nil, err + } + return encodeAck(true), nil + } +} + +func historyHandler(backend *backendclient.Client) Handler { + return func(ctx context.Context, req Request) ([]byte, error) { + in := fb.GetRootAsGameActionRequest(req.Payload, 0) + res, err := backend.History(ctx, req.UserID, string(in.GameId())) + if err != nil { + return nil, err + } + return encodeHistory(res), nil + } +} + +func chatListHandler(backend *backendclient.Client) Handler { + return func(ctx context.Context, req Request) ([]byte, error) { + in := fb.GetRootAsGameActionRequest(req.Payload, 0) + res, err := backend.ChatList(ctx, req.UserID, string(in.GameId())) + if err != nil { + return nil, err + } + return encodeChatList(res), nil + } +} + +func nudgeHandler(backend *backendclient.Client) Handler { + return func(ctx context.Context, req Request) ([]byte, error) { + in := fb.GetRootAsGameActionRequest(req.Payload, 0) + res, err := backend.Nudge(ctx, req.UserID, string(in.GameId())) + if err != nil { + return nil, err + } + return encodeChat(res), nil + } +} diff --git a/pkg/fbs/scrabble.fbs b/pkg/fbs/scrabble.fbs index f333587..ef8fda4 100644 --- a/pkg/fbs/scrabble.fbs +++ b/pkg/fbs/scrabble.fbs @@ -23,13 +23,15 @@ table TileRecord { blank:bool; } -// SeatView is one seat's public standing in a game. +// SeatView is one seat's public standing in a game. display_name is resolved by the +// backend from the account store (added trailing — backward-compatible). table SeatView { seat:int; account_id:string; score:int; hints_used:int; is_winner:bool; + display_name:string; } // GameView is the shared (non-private) game summary. @@ -143,6 +145,67 @@ table StateView { hints_remaining:int; } +// GameActionRequest carries just a game id (pass / resign / hint / history). +table GameActionRequest { + game_id:string; +} + +// ExchangeRequest swaps the listed rack tiles back into the bag. +table ExchangeRequest { + game_id:string; + tiles:[string]; +} + +// EvalRequest previews a tentative play without committing it. +table EvalRequest { + game_id:string; + dir:string; + tiles:[TileRecord]; +} + +// EvalResult is an unlimited move preview: legality, score and the words formed. +table EvalResult { + legal:bool; + score:int; + words:[string]; +} + +// CheckWordRequest looks a word up in the game's pinned dictionary. +table CheckWordRequest { + game_id:string; + word:string; +} + +// WordCheckResult is the dictionary lookup outcome. +table WordCheckResult { + word:string; + legal:bool; +} + +// ComplaintRequest disputes a word-check result. +table ComplaintRequest { + game_id:string; + word:string; + note:string; +} + +// HintResult is the top-ranked move plus the remaining hint budget. +table HintResult { + move:MoveRecord; + hints_remaining:int; +} + +// History is a game's decoded move journal — the source for client board replay. +table History { + game_id:string; + moves:[MoveRecord]; +} + +// GameList is the caller's games (active and finished) for the lobby. +table GameList { + games:[GameView]; +} + // --- lobby (authenticated) --- // EnqueueRequest joins the per-variant auto-match pool. @@ -174,6 +237,11 @@ table ChatMessage { created_at_unix:long; } +// ChatList is a game's chat history. +table ChatList { + messages:[ChatMessage]; +} + // --- push event payloads --- // YourTurnEvent signals that it is now the recipient's turn. diff --git a/pkg/fbs/scrabblefb/ChatList.go b/pkg/fbs/scrabblefb/ChatList.go new file mode 100644 index 0000000..f07bca6 --- /dev/null +++ b/pkg/fbs/scrabblefb/ChatList.go @@ -0,0 +1,75 @@ +// Code generated by the FlatBuffers compiler. DO NOT EDIT. + +package scrabblefb + +import ( + flatbuffers "github.com/google/flatbuffers/go" +) + +type ChatList struct { + _tab flatbuffers.Table +} + +func GetRootAsChatList(buf []byte, offset flatbuffers.UOffsetT) *ChatList { + n := flatbuffers.GetUOffsetT(buf[offset:]) + x := &ChatList{} + x.Init(buf, n+offset) + return x +} + +func FinishChatListBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.Finish(offset) +} + +func GetSizePrefixedRootAsChatList(buf []byte, offset flatbuffers.UOffsetT) *ChatList { + n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:]) + x := &ChatList{} + x.Init(buf, n+offset+flatbuffers.SizeUint32) + return x +} + +func FinishSizePrefixedChatListBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.FinishSizePrefixed(offset) +} + +func (rcv *ChatList) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *ChatList) Table() flatbuffers.Table { + return rcv._tab +} + +func (rcv *ChatList) Messages(obj *ChatMessage, j int) bool { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + x := rcv._tab.Vector(o) + x += flatbuffers.UOffsetT(j) * 4 + x = rcv._tab.Indirect(x) + obj.Init(rcv._tab.Bytes, x) + return true + } + return false +} + +func (rcv *ChatList) MessagesLength() int { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + return rcv._tab.VectorLen(o) + } + return 0 +} + +func ChatListStart(builder *flatbuffers.Builder) { + builder.StartObject(1) +} +func ChatListAddMessages(builder *flatbuffers.Builder, messages flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(messages), 0) +} +func ChatListStartMessagesVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { + return builder.StartVector(4, numElems, 4) +} +func ChatListEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { + return builder.EndObject() +} diff --git a/pkg/fbs/scrabblefb/CheckWordRequest.go b/pkg/fbs/scrabblefb/CheckWordRequest.go new file mode 100644 index 0000000..1d5759d --- /dev/null +++ b/pkg/fbs/scrabblefb/CheckWordRequest.go @@ -0,0 +1,71 @@ +// Code generated by the FlatBuffers compiler. DO NOT EDIT. + +package scrabblefb + +import ( + flatbuffers "github.com/google/flatbuffers/go" +) + +type CheckWordRequest struct { + _tab flatbuffers.Table +} + +func GetRootAsCheckWordRequest(buf []byte, offset flatbuffers.UOffsetT) *CheckWordRequest { + n := flatbuffers.GetUOffsetT(buf[offset:]) + x := &CheckWordRequest{} + x.Init(buf, n+offset) + return x +} + +func FinishCheckWordRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.Finish(offset) +} + +func GetSizePrefixedRootAsCheckWordRequest(buf []byte, offset flatbuffers.UOffsetT) *CheckWordRequest { + n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:]) + x := &CheckWordRequest{} + x.Init(buf, n+offset+flatbuffers.SizeUint32) + return x +} + +func FinishSizePrefixedCheckWordRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.FinishSizePrefixed(offset) +} + +func (rcv *CheckWordRequest) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *CheckWordRequest) Table() flatbuffers.Table { + return rcv._tab +} + +func (rcv *CheckWordRequest) GameId() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + +func (rcv *CheckWordRequest) Word() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + +func CheckWordRequestStart(builder *flatbuffers.Builder) { + builder.StartObject(2) +} +func CheckWordRequestAddGameId(builder *flatbuffers.Builder, gameId flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(gameId), 0) +} +func CheckWordRequestAddWord(builder *flatbuffers.Builder, word flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(word), 0) +} +func CheckWordRequestEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { + return builder.EndObject() +} diff --git a/pkg/fbs/scrabblefb/ComplaintRequest.go b/pkg/fbs/scrabblefb/ComplaintRequest.go new file mode 100644 index 0000000..a5cdea2 --- /dev/null +++ b/pkg/fbs/scrabblefb/ComplaintRequest.go @@ -0,0 +1,82 @@ +// Code generated by the FlatBuffers compiler. DO NOT EDIT. + +package scrabblefb + +import ( + flatbuffers "github.com/google/flatbuffers/go" +) + +type ComplaintRequest struct { + _tab flatbuffers.Table +} + +func GetRootAsComplaintRequest(buf []byte, offset flatbuffers.UOffsetT) *ComplaintRequest { + n := flatbuffers.GetUOffsetT(buf[offset:]) + x := &ComplaintRequest{} + x.Init(buf, n+offset) + return x +} + +func FinishComplaintRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.Finish(offset) +} + +func GetSizePrefixedRootAsComplaintRequest(buf []byte, offset flatbuffers.UOffsetT) *ComplaintRequest { + n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:]) + x := &ComplaintRequest{} + x.Init(buf, n+offset+flatbuffers.SizeUint32) + return x +} + +func FinishSizePrefixedComplaintRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.FinishSizePrefixed(offset) +} + +func (rcv *ComplaintRequest) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *ComplaintRequest) Table() flatbuffers.Table { + return rcv._tab +} + +func (rcv *ComplaintRequest) GameId() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + +func (rcv *ComplaintRequest) Word() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + +func (rcv *ComplaintRequest) Note() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(8)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + +func ComplaintRequestStart(builder *flatbuffers.Builder) { + builder.StartObject(3) +} +func ComplaintRequestAddGameId(builder *flatbuffers.Builder, gameId flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(gameId), 0) +} +func ComplaintRequestAddWord(builder *flatbuffers.Builder, word flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(word), 0) +} +func ComplaintRequestAddNote(builder *flatbuffers.Builder, note flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(2, flatbuffers.UOffsetT(note), 0) +} +func ComplaintRequestEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { + return builder.EndObject() +} diff --git a/pkg/fbs/scrabblefb/EvalRequest.go b/pkg/fbs/scrabblefb/EvalRequest.go new file mode 100644 index 0000000..7eeebae --- /dev/null +++ b/pkg/fbs/scrabblefb/EvalRequest.go @@ -0,0 +1,97 @@ +// Code generated by the FlatBuffers compiler. DO NOT EDIT. + +package scrabblefb + +import ( + flatbuffers "github.com/google/flatbuffers/go" +) + +type EvalRequest struct { + _tab flatbuffers.Table +} + +func GetRootAsEvalRequest(buf []byte, offset flatbuffers.UOffsetT) *EvalRequest { + n := flatbuffers.GetUOffsetT(buf[offset:]) + x := &EvalRequest{} + x.Init(buf, n+offset) + return x +} + +func FinishEvalRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.Finish(offset) +} + +func GetSizePrefixedRootAsEvalRequest(buf []byte, offset flatbuffers.UOffsetT) *EvalRequest { + n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:]) + x := &EvalRequest{} + x.Init(buf, n+offset+flatbuffers.SizeUint32) + return x +} + +func FinishSizePrefixedEvalRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.FinishSizePrefixed(offset) +} + +func (rcv *EvalRequest) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *EvalRequest) Table() flatbuffers.Table { + return rcv._tab +} + +func (rcv *EvalRequest) GameId() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + +func (rcv *EvalRequest) Dir() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + +func (rcv *EvalRequest) Tiles(obj *TileRecord, j int) bool { + o := flatbuffers.UOffsetT(rcv._tab.Offset(8)) + if o != 0 { + x := rcv._tab.Vector(o) + x += flatbuffers.UOffsetT(j) * 4 + x = rcv._tab.Indirect(x) + obj.Init(rcv._tab.Bytes, x) + return true + } + return false +} + +func (rcv *EvalRequest) TilesLength() int { + o := flatbuffers.UOffsetT(rcv._tab.Offset(8)) + if o != 0 { + return rcv._tab.VectorLen(o) + } + return 0 +} + +func EvalRequestStart(builder *flatbuffers.Builder) { + builder.StartObject(3) +} +func EvalRequestAddGameId(builder *flatbuffers.Builder, gameId flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(gameId), 0) +} +func EvalRequestAddDir(builder *flatbuffers.Builder, dir flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(dir), 0) +} +func EvalRequestAddTiles(builder *flatbuffers.Builder, tiles flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(2, flatbuffers.UOffsetT(tiles), 0) +} +func EvalRequestStartTilesVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { + return builder.StartVector(4, numElems, 4) +} +func EvalRequestEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { + return builder.EndObject() +} diff --git a/pkg/fbs/scrabblefb/EvalResult.go b/pkg/fbs/scrabblefb/EvalResult.go new file mode 100644 index 0000000..0255618 --- /dev/null +++ b/pkg/fbs/scrabblefb/EvalResult.go @@ -0,0 +1,102 @@ +// Code generated by the FlatBuffers compiler. DO NOT EDIT. + +package scrabblefb + +import ( + flatbuffers "github.com/google/flatbuffers/go" +) + +type EvalResult struct { + _tab flatbuffers.Table +} + +func GetRootAsEvalResult(buf []byte, offset flatbuffers.UOffsetT) *EvalResult { + n := flatbuffers.GetUOffsetT(buf[offset:]) + x := &EvalResult{} + x.Init(buf, n+offset) + return x +} + +func FinishEvalResultBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.Finish(offset) +} + +func GetSizePrefixedRootAsEvalResult(buf []byte, offset flatbuffers.UOffsetT) *EvalResult { + n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:]) + x := &EvalResult{} + x.Init(buf, n+offset+flatbuffers.SizeUint32) + return x +} + +func FinishSizePrefixedEvalResultBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.FinishSizePrefixed(offset) +} + +func (rcv *EvalResult) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *EvalResult) Table() flatbuffers.Table { + return rcv._tab +} + +func (rcv *EvalResult) Legal() bool { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + return rcv._tab.GetBool(o + rcv._tab.Pos) + } + return false +} + +func (rcv *EvalResult) MutateLegal(n bool) bool { + return rcv._tab.MutateBoolSlot(4, n) +} + +func (rcv *EvalResult) Score() int32 { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + return rcv._tab.GetInt32(o + rcv._tab.Pos) + } + return 0 +} + +func (rcv *EvalResult) MutateScore(n int32) bool { + return rcv._tab.MutateInt32Slot(6, n) +} + +func (rcv *EvalResult) Words(j int) []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(8)) + if o != 0 { + a := rcv._tab.Vector(o) + return rcv._tab.ByteVector(a + flatbuffers.UOffsetT(j*4)) + } + return nil +} + +func (rcv *EvalResult) WordsLength() int { + o := flatbuffers.UOffsetT(rcv._tab.Offset(8)) + if o != 0 { + return rcv._tab.VectorLen(o) + } + return 0 +} + +func EvalResultStart(builder *flatbuffers.Builder) { + builder.StartObject(3) +} +func EvalResultAddLegal(builder *flatbuffers.Builder, legal bool) { + builder.PrependBoolSlot(0, legal, false) +} +func EvalResultAddScore(builder *flatbuffers.Builder, score int32) { + builder.PrependInt32Slot(1, score, 0) +} +func EvalResultAddWords(builder *flatbuffers.Builder, words flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(2, flatbuffers.UOffsetT(words), 0) +} +func EvalResultStartWordsVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { + return builder.StartVector(4, numElems, 4) +} +func EvalResultEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { + return builder.EndObject() +} diff --git a/pkg/fbs/scrabblefb/ExchangeRequest.go b/pkg/fbs/scrabblefb/ExchangeRequest.go new file mode 100644 index 0000000..0226c5e --- /dev/null +++ b/pkg/fbs/scrabblefb/ExchangeRequest.go @@ -0,0 +1,83 @@ +// Code generated by the FlatBuffers compiler. DO NOT EDIT. + +package scrabblefb + +import ( + flatbuffers "github.com/google/flatbuffers/go" +) + +type ExchangeRequest struct { + _tab flatbuffers.Table +} + +func GetRootAsExchangeRequest(buf []byte, offset flatbuffers.UOffsetT) *ExchangeRequest { + n := flatbuffers.GetUOffsetT(buf[offset:]) + x := &ExchangeRequest{} + x.Init(buf, n+offset) + return x +} + +func FinishExchangeRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.Finish(offset) +} + +func GetSizePrefixedRootAsExchangeRequest(buf []byte, offset flatbuffers.UOffsetT) *ExchangeRequest { + n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:]) + x := &ExchangeRequest{} + x.Init(buf, n+offset+flatbuffers.SizeUint32) + return x +} + +func FinishSizePrefixedExchangeRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.FinishSizePrefixed(offset) +} + +func (rcv *ExchangeRequest) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *ExchangeRequest) Table() flatbuffers.Table { + return rcv._tab +} + +func (rcv *ExchangeRequest) GameId() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + +func (rcv *ExchangeRequest) Tiles(j int) []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + a := rcv._tab.Vector(o) + return rcv._tab.ByteVector(a + flatbuffers.UOffsetT(j*4)) + } + return nil +} + +func (rcv *ExchangeRequest) TilesLength() int { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + return rcv._tab.VectorLen(o) + } + return 0 +} + +func ExchangeRequestStart(builder *flatbuffers.Builder) { + builder.StartObject(2) +} +func ExchangeRequestAddGameId(builder *flatbuffers.Builder, gameId flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(gameId), 0) +} +func ExchangeRequestAddTiles(builder *flatbuffers.Builder, tiles flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(tiles), 0) +} +func ExchangeRequestStartTilesVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { + return builder.StartVector(4, numElems, 4) +} +func ExchangeRequestEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { + return builder.EndObject() +} diff --git a/pkg/fbs/scrabblefb/GameActionRequest.go b/pkg/fbs/scrabblefb/GameActionRequest.go new file mode 100644 index 0000000..f654d10 --- /dev/null +++ b/pkg/fbs/scrabblefb/GameActionRequest.go @@ -0,0 +1,60 @@ +// Code generated by the FlatBuffers compiler. DO NOT EDIT. + +package scrabblefb + +import ( + flatbuffers "github.com/google/flatbuffers/go" +) + +type GameActionRequest struct { + _tab flatbuffers.Table +} + +func GetRootAsGameActionRequest(buf []byte, offset flatbuffers.UOffsetT) *GameActionRequest { + n := flatbuffers.GetUOffsetT(buf[offset:]) + x := &GameActionRequest{} + x.Init(buf, n+offset) + return x +} + +func FinishGameActionRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.Finish(offset) +} + +func GetSizePrefixedRootAsGameActionRequest(buf []byte, offset flatbuffers.UOffsetT) *GameActionRequest { + n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:]) + x := &GameActionRequest{} + x.Init(buf, n+offset+flatbuffers.SizeUint32) + return x +} + +func FinishSizePrefixedGameActionRequestBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.FinishSizePrefixed(offset) +} + +func (rcv *GameActionRequest) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *GameActionRequest) Table() flatbuffers.Table { + return rcv._tab +} + +func (rcv *GameActionRequest) GameId() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + +func GameActionRequestStart(builder *flatbuffers.Builder) { + builder.StartObject(1) +} +func GameActionRequestAddGameId(builder *flatbuffers.Builder, gameId flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(gameId), 0) +} +func GameActionRequestEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { + return builder.EndObject() +} diff --git a/pkg/fbs/scrabblefb/GameList.go b/pkg/fbs/scrabblefb/GameList.go new file mode 100644 index 0000000..039e712 --- /dev/null +++ b/pkg/fbs/scrabblefb/GameList.go @@ -0,0 +1,75 @@ +// Code generated by the FlatBuffers compiler. DO NOT EDIT. + +package scrabblefb + +import ( + flatbuffers "github.com/google/flatbuffers/go" +) + +type GameList struct { + _tab flatbuffers.Table +} + +func GetRootAsGameList(buf []byte, offset flatbuffers.UOffsetT) *GameList { + n := flatbuffers.GetUOffsetT(buf[offset:]) + x := &GameList{} + x.Init(buf, n+offset) + return x +} + +func FinishGameListBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.Finish(offset) +} + +func GetSizePrefixedRootAsGameList(buf []byte, offset flatbuffers.UOffsetT) *GameList { + n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:]) + x := &GameList{} + x.Init(buf, n+offset+flatbuffers.SizeUint32) + return x +} + +func FinishSizePrefixedGameListBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.FinishSizePrefixed(offset) +} + +func (rcv *GameList) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *GameList) Table() flatbuffers.Table { + return rcv._tab +} + +func (rcv *GameList) Games(obj *GameView, j int) bool { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + x := rcv._tab.Vector(o) + x += flatbuffers.UOffsetT(j) * 4 + x = rcv._tab.Indirect(x) + obj.Init(rcv._tab.Bytes, x) + return true + } + return false +} + +func (rcv *GameList) GamesLength() int { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + return rcv._tab.VectorLen(o) + } + return 0 +} + +func GameListStart(builder *flatbuffers.Builder) { + builder.StartObject(1) +} +func GameListAddGames(builder *flatbuffers.Builder, games flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(games), 0) +} +func GameListStartGamesVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { + return builder.StartVector(4, numElems, 4) +} +func GameListEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { + return builder.EndObject() +} diff --git a/pkg/fbs/scrabblefb/HintResult.go b/pkg/fbs/scrabblefb/HintResult.go new file mode 100644 index 0000000..bad7b75 --- /dev/null +++ b/pkg/fbs/scrabblefb/HintResult.go @@ -0,0 +1,80 @@ +// Code generated by the FlatBuffers compiler. DO NOT EDIT. + +package scrabblefb + +import ( + flatbuffers "github.com/google/flatbuffers/go" +) + +type HintResult struct { + _tab flatbuffers.Table +} + +func GetRootAsHintResult(buf []byte, offset flatbuffers.UOffsetT) *HintResult { + n := flatbuffers.GetUOffsetT(buf[offset:]) + x := &HintResult{} + x.Init(buf, n+offset) + return x +} + +func FinishHintResultBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.Finish(offset) +} + +func GetSizePrefixedRootAsHintResult(buf []byte, offset flatbuffers.UOffsetT) *HintResult { + n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:]) + x := &HintResult{} + x.Init(buf, n+offset+flatbuffers.SizeUint32) + return x +} + +func FinishSizePrefixedHintResultBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.FinishSizePrefixed(offset) +} + +func (rcv *HintResult) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *HintResult) Table() flatbuffers.Table { + return rcv._tab +} + +func (rcv *HintResult) Move(obj *MoveRecord) *MoveRecord { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + x := rcv._tab.Indirect(o + rcv._tab.Pos) + if obj == nil { + obj = new(MoveRecord) + } + obj.Init(rcv._tab.Bytes, x) + return obj + } + return nil +} + +func (rcv *HintResult) HintsRemaining() int32 { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + return rcv._tab.GetInt32(o + rcv._tab.Pos) + } + return 0 +} + +func (rcv *HintResult) MutateHintsRemaining(n int32) bool { + return rcv._tab.MutateInt32Slot(6, n) +} + +func HintResultStart(builder *flatbuffers.Builder) { + builder.StartObject(2) +} +func HintResultAddMove(builder *flatbuffers.Builder, move flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(move), 0) +} +func HintResultAddHintsRemaining(builder *flatbuffers.Builder, hintsRemaining int32) { + builder.PrependInt32Slot(1, hintsRemaining, 0) +} +func HintResultEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { + return builder.EndObject() +} diff --git a/pkg/fbs/scrabblefb/History.go b/pkg/fbs/scrabblefb/History.go new file mode 100644 index 0000000..681b480 --- /dev/null +++ b/pkg/fbs/scrabblefb/History.go @@ -0,0 +1,86 @@ +// Code generated by the FlatBuffers compiler. DO NOT EDIT. + +package scrabblefb + +import ( + flatbuffers "github.com/google/flatbuffers/go" +) + +type History struct { + _tab flatbuffers.Table +} + +func GetRootAsHistory(buf []byte, offset flatbuffers.UOffsetT) *History { + n := flatbuffers.GetUOffsetT(buf[offset:]) + x := &History{} + x.Init(buf, n+offset) + return x +} + +func FinishHistoryBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.Finish(offset) +} + +func GetSizePrefixedRootAsHistory(buf []byte, offset flatbuffers.UOffsetT) *History { + n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:]) + x := &History{} + x.Init(buf, n+offset+flatbuffers.SizeUint32) + return x +} + +func FinishSizePrefixedHistoryBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.FinishSizePrefixed(offset) +} + +func (rcv *History) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *History) Table() flatbuffers.Table { + return rcv._tab +} + +func (rcv *History) GameId() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + +func (rcv *History) Moves(obj *MoveRecord, j int) bool { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + x := rcv._tab.Vector(o) + x += flatbuffers.UOffsetT(j) * 4 + x = rcv._tab.Indirect(x) + obj.Init(rcv._tab.Bytes, x) + return true + } + return false +} + +func (rcv *History) MovesLength() int { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + return rcv._tab.VectorLen(o) + } + return 0 +} + +func HistoryStart(builder *flatbuffers.Builder) { + builder.StartObject(2) +} +func HistoryAddGameId(builder *flatbuffers.Builder, gameId flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(gameId), 0) +} +func HistoryAddMoves(builder *flatbuffers.Builder, moves flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(1, flatbuffers.UOffsetT(moves), 0) +} +func HistoryStartMovesVector(builder *flatbuffers.Builder, numElems int) flatbuffers.UOffsetT { + return builder.StartVector(4, numElems, 4) +} +func HistoryEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { + return builder.EndObject() +} diff --git a/pkg/fbs/scrabblefb/SeatView.go b/pkg/fbs/scrabblefb/SeatView.go index 699fa73..f9d78e2 100644 --- a/pkg/fbs/scrabblefb/SeatView.go +++ b/pkg/fbs/scrabblefb/SeatView.go @@ -97,8 +97,16 @@ func (rcv *SeatView) MutateIsWinner(n bool) bool { return rcv._tab.MutateBoolSlot(12, n) } +func (rcv *SeatView) DisplayName() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(14)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + func SeatViewStart(builder *flatbuffers.Builder) { - builder.StartObject(5) + builder.StartObject(6) } func SeatViewAddSeat(builder *flatbuffers.Builder, seat int32) { builder.PrependInt32Slot(0, seat, 0) @@ -115,6 +123,9 @@ func SeatViewAddHintsUsed(builder *flatbuffers.Builder, hintsUsed int32) { func SeatViewAddIsWinner(builder *flatbuffers.Builder, isWinner bool) { builder.PrependBoolSlot(4, isWinner, false) } +func SeatViewAddDisplayName(builder *flatbuffers.Builder, displayName flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(5, flatbuffers.UOffsetT(displayName), 0) +} func SeatViewEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { return builder.EndObject() } diff --git a/pkg/fbs/scrabblefb/WordCheckResult.go b/pkg/fbs/scrabblefb/WordCheckResult.go new file mode 100644 index 0000000..da258ed --- /dev/null +++ b/pkg/fbs/scrabblefb/WordCheckResult.go @@ -0,0 +1,75 @@ +// Code generated by the FlatBuffers compiler. DO NOT EDIT. + +package scrabblefb + +import ( + flatbuffers "github.com/google/flatbuffers/go" +) + +type WordCheckResult struct { + _tab flatbuffers.Table +} + +func GetRootAsWordCheckResult(buf []byte, offset flatbuffers.UOffsetT) *WordCheckResult { + n := flatbuffers.GetUOffsetT(buf[offset:]) + x := &WordCheckResult{} + x.Init(buf, n+offset) + return x +} + +func FinishWordCheckResultBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.Finish(offset) +} + +func GetSizePrefixedRootAsWordCheckResult(buf []byte, offset flatbuffers.UOffsetT) *WordCheckResult { + n := flatbuffers.GetUOffsetT(buf[offset+flatbuffers.SizeUint32:]) + x := &WordCheckResult{} + x.Init(buf, n+offset+flatbuffers.SizeUint32) + return x +} + +func FinishSizePrefixedWordCheckResultBuffer(builder *flatbuffers.Builder, offset flatbuffers.UOffsetT) { + builder.FinishSizePrefixed(offset) +} + +func (rcv *WordCheckResult) Init(buf []byte, i flatbuffers.UOffsetT) { + rcv._tab.Bytes = buf + rcv._tab.Pos = i +} + +func (rcv *WordCheckResult) Table() flatbuffers.Table { + return rcv._tab +} + +func (rcv *WordCheckResult) Word() []byte { + o := flatbuffers.UOffsetT(rcv._tab.Offset(4)) + if o != 0 { + return rcv._tab.ByteVector(o + rcv._tab.Pos) + } + return nil +} + +func (rcv *WordCheckResult) Legal() bool { + o := flatbuffers.UOffsetT(rcv._tab.Offset(6)) + if o != 0 { + return rcv._tab.GetBool(o + rcv._tab.Pos) + } + return false +} + +func (rcv *WordCheckResult) MutateLegal(n bool) bool { + return rcv._tab.MutateBoolSlot(6, n) +} + +func WordCheckResultStart(builder *flatbuffers.Builder) { + builder.StartObject(2) +} +func WordCheckResultAddWord(builder *flatbuffers.Builder, word flatbuffers.UOffsetT) { + builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(word), 0) +} +func WordCheckResultAddLegal(builder *flatbuffers.Builder, legal bool) { + builder.PrependBoolSlot(1, legal, false) +} +func WordCheckResultEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT { + return builder.EndObject() +} diff --git a/ui/buf.gen.yaml b/ui/buf.gen.yaml new file mode 100644 index 0000000..cf2443b --- /dev/null +++ b/ui/buf.gen.yaml @@ -0,0 +1,9 @@ +# Generates the TypeScript Connect client for the edge envelope service from the +# same gateway/proto/edge/v1/edge.proto the Go gateway uses. The committed output +# lives under src/gen/edge/; CI only builds it (dev-time codegen, like pkg/Makefile). +version: v2 +plugins: + - local: ./node_modules/.bin/protoc-gen-es + out: src/gen + opt: + - target=ts diff --git a/ui/package.json b/ui/package.json index 04a1dfe..a00f5cd 100644 --- a/ui/package.json +++ b/ui/package.json @@ -10,11 +10,19 @@ "build": "vite build", "preview": "vite preview", "check": "svelte-check --tsconfig ./tsconfig.json", + "codegen": "rm -rf src/gen && flatc --ts -o src/gen/fbs ../pkg/fbs/scrabble.fbs && buf generate ../gateway --template buf.gen.yaml", "test:unit": "vitest run", "test:watch": "vitest", "test:e2e": "playwright test" }, + "dependencies": { + "@bufbuild/protobuf": "^2.12.0", + "@connectrpc/connect": "^2.1.0", + "@connectrpc/connect-web": "^2.1.0", + "flatbuffers": "^25.9.23" + }, "devDependencies": { + "@bufbuild/protoc-gen-es": "^2.12.0", "@playwright/test": "^1.49.0", "@sveltejs/vite-plugin-svelte": "^5.0.0", "@types/node": "^22.10.0", diff --git a/ui/pnpm-lock.yaml b/ui/pnpm-lock.yaml index eea65f0..9532542 100644 --- a/ui/pnpm-lock.yaml +++ b/ui/pnpm-lock.yaml @@ -7,7 +7,23 @@ settings: importers: .: + dependencies: + '@bufbuild/protobuf': + specifier: ^2.12.0 + version: 2.12.0 + '@connectrpc/connect': + specifier: ^2.1.0 + version: 2.1.1(@bufbuild/protobuf@2.12.0) + '@connectrpc/connect-web': + specifier: ^2.1.0 + version: 2.1.1(@bufbuild/protobuf@2.12.0)(@connectrpc/connect@2.1.1(@bufbuild/protobuf@2.12.0)) + flatbuffers: + specifier: ^25.9.23 + version: 25.9.23 devDependencies: + '@bufbuild/protoc-gen-es': + specifier: ^2.12.0 + version: 2.12.0(@bufbuild/protobuf@2.12.0) '@playwright/test': specifier: ^1.49.0 version: 1.60.0 @@ -35,6 +51,33 @@ importers: packages: + '@bufbuild/protobuf@2.12.0': + resolution: {integrity: sha512-B/XlCaFIP8LOwzo+bz5uFzATYokcwCKQcghqnlfwSmM5eX/qTkvDBnDPs+gXtX/RyjxJ4DRikECcPJbyALA8FA==} + + '@bufbuild/protoc-gen-es@2.12.0': + resolution: {integrity: sha512-d9htF6jEkSwPbp9d/vSmZOBF7eeG18AvTMKmVg4I23afnrQOxL2w3WOXa9TaufMCyu24QakEUb4vux8apI5e7A==} + engines: {node: '>=20'} + hasBin: true + peerDependencies: + '@bufbuild/protobuf': 2.12.0 + peerDependenciesMeta: + '@bufbuild/protobuf': + optional: true + + '@bufbuild/protoplugin@2.12.0': + resolution: {integrity: sha512-ORlDITp8AFUXzIhLRoMCG+ud+D3MPKWb5HQXBoskMMnjeyEjE1H1qLonVNPyOr8lkx3xSfYUo8a0dvOZJVAzow==} + + '@connectrpc/connect-web@2.1.1': + resolution: {integrity: sha512-J8317Q2MaFRCT1jzVR1o06bZhDIBmU0UAzWx6xOIXzOq8+k71/+k7MUF7AwcBUX+34WIvbm5syRgC5HXQA8fOg==} + peerDependencies: + '@bufbuild/protobuf': ^2.7.0 + '@connectrpc/connect': 2.1.1 + + '@connectrpc/connect@2.1.1': + resolution: {integrity: sha512-JzhkaTvM73m2K1URT6tv53k2RwngSmCXLZJgK580qNQOXRzZRR/BCMfZw3h+90JpnG6XksP5bYT+cz0rpUzUWQ==} + peerDependencies: + '@bufbuild/protobuf': ^2.7.0 + '@esbuild/aix-ppc64@0.25.12': resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} engines: {node: '>=18'} @@ -385,6 +428,11 @@ packages: '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@typescript/vfs@1.6.4': + resolution: {integrity: sha512-PJFXFS4ZJKiJ9Qiuix6Dz/OwEIqHD7Dme1UwZhTK11vR+5dqW2ACbdndWQexBzCx+CPuMe5WBYQWCsFyGlQLlQ==} + peerDependencies: + typescript: '*' + '@vitest/expect@3.2.6': resolution: {integrity: sha512-1+7q9BtaKzEmO+fmNT3kYvoNn5Y71XWAx2Q5HRim4tTVRQVRv4uJFAQ5FbK0OPUeNP/WmVCpxYxoJdvuHVjzBQ==} @@ -506,6 +554,9 @@ packages: picomatch: optional: true + flatbuffers@25.9.23: + resolution: {integrity: sha512-MI1qs7Lo4Syw0EOzUl0xjs2lsoeqFku44KpngfIduHBYvzm8h2+7K8YMQh1JtVVVrUvhLpNwqVi4DERegUJhPQ==} + fsevents@2.3.2: resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -638,6 +689,11 @@ packages: resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} engines: {node: '>=14.0.0'} + typescript@5.4.5: + resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} + engines: {node: '>=14.17'} + hasBin: true + typescript@5.9.3: resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} engines: {node: '>=14.17'} @@ -737,6 +793,33 @@ packages: snapshots: + '@bufbuild/protobuf@2.12.0': {} + + '@bufbuild/protoc-gen-es@2.12.0(@bufbuild/protobuf@2.12.0)': + dependencies: + '@bufbuild/protoplugin': 2.12.0 + optionalDependencies: + '@bufbuild/protobuf': 2.12.0 + transitivePeerDependencies: + - supports-color + + '@bufbuild/protoplugin@2.12.0': + dependencies: + '@bufbuild/protobuf': 2.12.0 + '@typescript/vfs': 1.6.4(typescript@5.4.5) + typescript: 5.4.5 + transitivePeerDependencies: + - supports-color + + '@connectrpc/connect-web@2.1.1(@bufbuild/protobuf@2.12.0)(@connectrpc/connect@2.1.1(@bufbuild/protobuf@2.12.0))': + dependencies: + '@bufbuild/protobuf': 2.12.0 + '@connectrpc/connect': 2.1.1(@bufbuild/protobuf@2.12.0) + + '@connectrpc/connect@2.1.1(@bufbuild/protobuf@2.12.0)': + dependencies: + '@bufbuild/protobuf': 2.12.0 + '@esbuild/aix-ppc64@0.25.12': optional: true @@ -954,6 +1037,13 @@ snapshots: '@types/trusted-types@2.0.7': {} + '@typescript/vfs@1.6.4(typescript@5.4.5)': + dependencies: + debug: 4.4.3 + typescript: 5.4.5 + transitivePeerDependencies: + - supports-color + '@vitest/expect@3.2.6': dependencies: '@types/chai': 5.2.3 @@ -1079,6 +1169,8 @@ snapshots: optionalDependencies: picomatch: 4.0.4 + flatbuffers@25.9.23: {} + fsevents@2.3.2: optional: true @@ -1226,6 +1318,8 @@ snapshots: tinyspy@4.0.4: {} + typescript@5.4.5: {} + typescript@5.9.3: {} undici-types@6.21.0: {} diff --git a/ui/src/gen/edge/v1/edge_pb.ts b/ui/src/gen/edge/v1/edge_pb.ts new file mode 100644 index 0000000..db58ee8 --- /dev/null +++ b/ui/src/gen/edge/v1/edge_pb.ts @@ -0,0 +1,159 @@ +// @generated by protoc-gen-es v2.12.0 with parameter "target=ts" +// @generated from file edge/v1/edge.proto (package scrabble.edge.v1, syntax proto3) +/* eslint-disable */ + +// Package scrabble.edge.v1 is the client <-> gateway Connect-RPC contract. It is +// deliberately minimal (ARCHITECTURE.md §2): a single unary Execute that routes +// by message_type, and a server-streaming Subscribe for the in-app live channel. +// The actual request/response and event bodies travel as FlatBuffers bytes in the +// payload fields (pkg/fbs). The session token rides in the Authorization header, +// not the envelope (no per-request signing — ARCHITECTURE.md §3). + +import type { GenFile, GenMessage, GenService } from "@bufbuild/protobuf/codegenv2"; +import { fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv2"; +import type { Message } from "@bufbuild/protobuf"; + +/** + * Describes the file edge/v1/edge.proto. + */ +export const file_edge_v1_edge: GenFile = /*@__PURE__*/ + fileDesc("ChJlZGdlL3YxL2VkZ2UucHJvdG8SEHNjcmFiYmxlLmVkZ2UudjEiSwoORXhlY3V0ZVJlcXVlc3QSFAoMbWVzc2FnZV90eXBlGAEgASgJEg8KB3BheWxvYWQYAiABKAwSEgoKcmVxdWVzdF9pZBgDIAEoCSJLCg9FeGVjdXRlUmVzcG9uc2USEgoKcmVxdWVzdF9pZBgBIAEoCRITCgtyZXN1bHRfY29kZRgCIAEoCRIPCgdwYXlsb2FkGAMgASgMIhIKEFN1YnNjcmliZVJlcXVlc3QiOAoFRXZlbnQSDAoEa2luZBgBIAEoCRIPCgdwYXlsb2FkGAIgASgMEhAKCGV2ZW50X2lkGAMgASgJMqUBCgdHYXRld2F5Ek4KB0V4ZWN1dGUSIC5zY3JhYmJsZS5lZGdlLnYxLkV4ZWN1dGVSZXF1ZXN0GiEuc2NyYWJibGUuZWRnZS52MS5FeGVjdXRlUmVzcG9uc2USSgoJU3Vic2NyaWJlEiIuc2NyYWJibGUuZWRnZS52MS5TdWJzY3JpYmVSZXF1ZXN0Ghcuc2NyYWJibGUuZWRnZS52MS5FdmVudDABQidaJXNjcmFiYmxlL2dhdGV3YXkvcHJvdG8vZWRnZS92MTtlZGdldjFiBnByb3RvMw"); + +/** + * ExecuteRequest is the unary envelope. message_type selects the operation; + * payload is its FlatBuffers-encoded request body; request_id is an optional + * client correlation id echoed back. + * + * @generated from message scrabble.edge.v1.ExecuteRequest + */ +export type ExecuteRequest = Message<"scrabble.edge.v1.ExecuteRequest"> & { + /** + * @generated from field: string message_type = 1; + */ + messageType: string; + + /** + * @generated from field: bytes payload = 2; + */ + payload: Uint8Array; + + /** + * @generated from field: string request_id = 3; + */ + requestId: string; +}; + +/** + * Describes the message scrabble.edge.v1.ExecuteRequest. + * Use `create(ExecuteRequestSchema)` to create a new message. + */ +export const ExecuteRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_edge_v1_edge, 0); + +/** + * ExecuteResponse is the unary reply. result_code is "ok" on success or a stable + * error code; payload is the FlatBuffers-encoded response body (empty on error). + * + * @generated from message scrabble.edge.v1.ExecuteResponse + */ +export type ExecuteResponse = Message<"scrabble.edge.v1.ExecuteResponse"> & { + /** + * @generated from field: string request_id = 1; + */ + requestId: string; + + /** + * @generated from field: string result_code = 2; + */ + resultCode: string; + + /** + * @generated from field: bytes payload = 3; + */ + payload: Uint8Array; +}; + +/** + * Describes the message scrabble.edge.v1.ExecuteResponse. + * Use `create(ExecuteResponseSchema)` to create a new message. + */ +export const ExecuteResponseSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_edge_v1_edge, 1); + +/** + * SubscribeRequest opens the live stream. It is empty: the session is taken from + * the Authorization header. + * + * @generated from message scrabble.edge.v1.SubscribeRequest + */ +export type SubscribeRequest = Message<"scrabble.edge.v1.SubscribeRequest"> & { +}; + +/** + * Describes the message scrabble.edge.v1.SubscribeRequest. + * Use `create(SubscribeRequestSchema)` to create a new message. + */ +export const SubscribeRequestSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_edge_v1_edge, 2); + +/** + * Event is one live event. kind is the notification catalog kind; payload is its + * FlatBuffers-encoded body; event_id is a correlation id. + * + * @generated from message scrabble.edge.v1.Event + */ +export type Event = Message<"scrabble.edge.v1.Event"> & { + /** + * @generated from field: string kind = 1; + */ + kind: string; + + /** + * @generated from field: bytes payload = 2; + */ + payload: Uint8Array; + + /** + * @generated from field: string event_id = 3; + */ + eventId: string; +}; + +/** + * Describes the message scrabble.edge.v1.Event. + * Use `create(EventSchema)` to create a new message. + */ +export const EventSchema: GenMessage = /*@__PURE__*/ + messageDesc(file_edge_v1_edge, 3); + +/** + * Gateway is the public edge service. + * + * @generated from service scrabble.edge.v1.Gateway + */ +export const Gateway: GenService<{ + /** + * Execute runs one unary operation identified by message_type. Auth operations + * (auth.*) are unauthenticated and return a minted session; all others require + * a valid session token in the Authorization header. + * + * @generated from rpc scrabble.edge.v1.Gateway.Execute + */ + execute: { + methodKind: "unary"; + input: typeof ExecuteRequestSchema; + output: typeof ExecuteResponseSchema; + }, + /** + * Subscribe opens the in-app live-event stream for the authenticated session. + * + * @generated from rpc scrabble.edge.v1.Gateway.Subscribe + */ + subscribe: { + methodKind: "server_streaming"; + input: typeof SubscribeRequestSchema; + output: typeof EventSchema; + }, +}> = /*@__PURE__*/ + serviceDesc(file_edge_v1_edge, 0); + diff --git a/ui/src/gen/fbs/scrabble.ts b/ui/src/gen/fbs/scrabble.ts new file mode 100644 index 0000000..1c482cb --- /dev/null +++ b/ui/src/gen/fbs/scrabble.ts @@ -0,0 +1,3 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +export * as scrabblefb from './scrabblefb.js'; diff --git a/ui/src/gen/fbs/scrabblefb.ts b/ui/src/gen/fbs/scrabblefb.ts new file mode 100644 index 0000000..fe1bf12 --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb.ts @@ -0,0 +1,36 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +export { Ack } from './scrabblefb/ack.js'; +export { ChatList } from './scrabblefb/chat-list.js'; +export { ChatMessage } from './scrabblefb/chat-message.js'; +export { ChatPostRequest } from './scrabblefb/chat-post-request.js'; +export { CheckWordRequest } from './scrabblefb/check-word-request.js'; +export { ComplaintRequest } from './scrabblefb/complaint-request.js'; +export { EmailLoginRequest } from './scrabblefb/email-login-request.js'; +export { EmailRequestRequest } from './scrabblefb/email-request-request.js'; +export { EnqueueRequest } from './scrabblefb/enqueue-request.js'; +export { EvalRequest } from './scrabblefb/eval-request.js'; +export { EvalResult } from './scrabblefb/eval-result.js'; +export { ExchangeRequest } from './scrabblefb/exchange-request.js'; +export { GameActionRequest } from './scrabblefb/game-action-request.js'; +export { GameList } from './scrabblefb/game-list.js'; +export { GameView } from './scrabblefb/game-view.js'; +export { GuestLoginRequest } from './scrabblefb/guest-login-request.js'; +export { HintResult } from './scrabblefb/hint-result.js'; +export { History } from './scrabblefb/history.js'; +export { MatchFoundEvent } from './scrabblefb/match-found-event.js'; +export { MatchResult } from './scrabblefb/match-result.js'; +export { MoveRecord } from './scrabblefb/move-record.js'; +export { MoveResult } from './scrabblefb/move-result.js'; +export { NudgeEvent } from './scrabblefb/nudge-event.js'; +export { OpponentMovedEvent } from './scrabblefb/opponent-moved-event.js'; +export { Profile } from './scrabblefb/profile.js'; +export { SeatView } from './scrabblefb/seat-view.js'; +export { Session } from './scrabblefb/session.js'; +export { StateRequest } from './scrabblefb/state-request.js'; +export { StateView } from './scrabblefb/state-view.js'; +export { SubmitPlayRequest } from './scrabblefb/submit-play-request.js'; +export { TelegramLoginRequest } from './scrabblefb/telegram-login-request.js'; +export { TileRecord } from './scrabblefb/tile-record.js'; +export { WordCheckResult } from './scrabblefb/word-check-result.js'; +export { YourTurnEvent } from './scrabblefb/your-turn-event.js'; diff --git a/ui/src/gen/fbs/scrabblefb/ack.ts b/ui/src/gen/fbs/scrabblefb/ack.ts new file mode 100644 index 0000000..d7567ee --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/ack.ts @@ -0,0 +1,46 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class Ack { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):Ack { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsAck(bb:flatbuffers.ByteBuffer, obj?:Ack):Ack { + return (obj || new Ack()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsAck(bb:flatbuffers.ByteBuffer, obj?:Ack):Ack { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new Ack()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +ok():boolean { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false; +} + +static startAck(builder:flatbuffers.Builder) { + builder.startObject(1); +} + +static addOk(builder:flatbuffers.Builder, ok:boolean) { + builder.addFieldInt8(0, +ok, +false); +} + +static endAck(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createAck(builder:flatbuffers.Builder, ok:boolean):flatbuffers.Offset { + Ack.startAck(builder); + Ack.addOk(builder, ok); + return Ack.endAck(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/chat-list.ts b/ui/src/gen/fbs/scrabblefb/chat-list.ts new file mode 100644 index 0000000..82422b8 --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/chat-list.ts @@ -0,0 +1,66 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +import { ChatMessage } from '../scrabblefb/chat-message.js'; + + +export class ChatList { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):ChatList { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsChatList(bb:flatbuffers.ByteBuffer, obj?:ChatList):ChatList { + return (obj || new ChatList()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsChatList(bb:flatbuffers.ByteBuffer, obj?:ChatList):ChatList { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new ChatList()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +messages(index: number, obj?:ChatMessage):ChatMessage|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? (obj || new ChatMessage()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null; +} + +messagesLength():number { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; +} + +static startChatList(builder:flatbuffers.Builder) { + builder.startObject(1); +} + +static addMessages(builder:flatbuffers.Builder, messagesOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, messagesOffset, 0); +} + +static createMessagesVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); +} + +static startMessagesVector(builder:flatbuffers.Builder, numElems:number) { + builder.startVector(4, numElems, 4); +} + +static endChatList(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createChatList(builder:flatbuffers.Builder, messagesOffset:flatbuffers.Offset):flatbuffers.Offset { + ChatList.startChatList(builder); + ChatList.addMessages(builder, messagesOffset); + return ChatList.endChatList(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/chat-message.ts b/ui/src/gen/fbs/scrabblefb/chat-message.ts new file mode 100644 index 0000000..bca7184 --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/chat-message.ts @@ -0,0 +1,106 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class ChatMessage { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):ChatMessage { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsChatMessage(bb:flatbuffers.ByteBuffer, obj?:ChatMessage):ChatMessage { + return (obj || new ChatMessage()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsChatMessage(bb:flatbuffers.ByteBuffer, obj?:ChatMessage):ChatMessage { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new ChatMessage()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +id():string|null +id(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +id(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +gameId():string|null +gameId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +gameId(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +senderId():string|null +senderId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +senderId(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +kind():string|null +kind(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +kind(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 10); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +body():string|null +body(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +body(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 12); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +createdAtUnix():bigint { + const offset = this.bb!.__offset(this.bb_pos, 14); + return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0'); +} + +static startChatMessage(builder:flatbuffers.Builder) { + builder.startObject(6); +} + +static addId(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, idOffset, 0); +} + +static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, gameIdOffset, 0); +} + +static addSenderId(builder:flatbuffers.Builder, senderIdOffset:flatbuffers.Offset) { + builder.addFieldOffset(2, senderIdOffset, 0); +} + +static addKind(builder:flatbuffers.Builder, kindOffset:flatbuffers.Offset) { + builder.addFieldOffset(3, kindOffset, 0); +} + +static addBody(builder:flatbuffers.Builder, bodyOffset:flatbuffers.Offset) { + builder.addFieldOffset(4, bodyOffset, 0); +} + +static addCreatedAtUnix(builder:flatbuffers.Builder, createdAtUnix:bigint) { + builder.addFieldInt64(5, createdAtUnix, BigInt('0')); +} + +static endChatMessage(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createChatMessage(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset, gameIdOffset:flatbuffers.Offset, senderIdOffset:flatbuffers.Offset, kindOffset:flatbuffers.Offset, bodyOffset:flatbuffers.Offset, createdAtUnix:bigint):flatbuffers.Offset { + ChatMessage.startChatMessage(builder); + ChatMessage.addId(builder, idOffset); + ChatMessage.addGameId(builder, gameIdOffset); + ChatMessage.addSenderId(builder, senderIdOffset); + ChatMessage.addKind(builder, kindOffset); + ChatMessage.addBody(builder, bodyOffset); + ChatMessage.addCreatedAtUnix(builder, createdAtUnix); + return ChatMessage.endChatMessage(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/chat-post-request.ts b/ui/src/gen/fbs/scrabblefb/chat-post-request.ts new file mode 100644 index 0000000..07adb61 --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/chat-post-request.ts @@ -0,0 +1,60 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class ChatPostRequest { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):ChatPostRequest { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsChatPostRequest(bb:flatbuffers.ByteBuffer, obj?:ChatPostRequest):ChatPostRequest { + return (obj || new ChatPostRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsChatPostRequest(bb:flatbuffers.ByteBuffer, obj?:ChatPostRequest):ChatPostRequest { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new ChatPostRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +gameId():string|null +gameId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +gameId(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +body():string|null +body(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +body(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +static startChatPostRequest(builder:flatbuffers.Builder) { + builder.startObject(2); +} + +static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, gameIdOffset, 0); +} + +static addBody(builder:flatbuffers.Builder, bodyOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, bodyOffset, 0); +} + +static endChatPostRequest(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createChatPostRequest(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset, bodyOffset:flatbuffers.Offset):flatbuffers.Offset { + ChatPostRequest.startChatPostRequest(builder); + ChatPostRequest.addGameId(builder, gameIdOffset); + ChatPostRequest.addBody(builder, bodyOffset); + return ChatPostRequest.endChatPostRequest(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/check-word-request.ts b/ui/src/gen/fbs/scrabblefb/check-word-request.ts new file mode 100644 index 0000000..8b2e17b --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/check-word-request.ts @@ -0,0 +1,60 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class CheckWordRequest { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):CheckWordRequest { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsCheckWordRequest(bb:flatbuffers.ByteBuffer, obj?:CheckWordRequest):CheckWordRequest { + return (obj || new CheckWordRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsCheckWordRequest(bb:flatbuffers.ByteBuffer, obj?:CheckWordRequest):CheckWordRequest { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new CheckWordRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +gameId():string|null +gameId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +gameId(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +word():string|null +word(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +word(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +static startCheckWordRequest(builder:flatbuffers.Builder) { + builder.startObject(2); +} + +static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, gameIdOffset, 0); +} + +static addWord(builder:flatbuffers.Builder, wordOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, wordOffset, 0); +} + +static endCheckWordRequest(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createCheckWordRequest(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset, wordOffset:flatbuffers.Offset):flatbuffers.Offset { + CheckWordRequest.startCheckWordRequest(builder); + CheckWordRequest.addGameId(builder, gameIdOffset); + CheckWordRequest.addWord(builder, wordOffset); + return CheckWordRequest.endCheckWordRequest(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/complaint-request.ts b/ui/src/gen/fbs/scrabblefb/complaint-request.ts new file mode 100644 index 0000000..85bf15e --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/complaint-request.ts @@ -0,0 +1,72 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class ComplaintRequest { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):ComplaintRequest { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsComplaintRequest(bb:flatbuffers.ByteBuffer, obj?:ComplaintRequest):ComplaintRequest { + return (obj || new ComplaintRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsComplaintRequest(bb:flatbuffers.ByteBuffer, obj?:ComplaintRequest):ComplaintRequest { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new ComplaintRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +gameId():string|null +gameId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +gameId(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +word():string|null +word(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +word(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +note():string|null +note(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +note(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +static startComplaintRequest(builder:flatbuffers.Builder) { + builder.startObject(3); +} + +static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, gameIdOffset, 0); +} + +static addWord(builder:flatbuffers.Builder, wordOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, wordOffset, 0); +} + +static addNote(builder:flatbuffers.Builder, noteOffset:flatbuffers.Offset) { + builder.addFieldOffset(2, noteOffset, 0); +} + +static endComplaintRequest(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createComplaintRequest(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset, wordOffset:flatbuffers.Offset, noteOffset:flatbuffers.Offset):flatbuffers.Offset { + ComplaintRequest.startComplaintRequest(builder); + ComplaintRequest.addGameId(builder, gameIdOffset); + ComplaintRequest.addWord(builder, wordOffset); + ComplaintRequest.addNote(builder, noteOffset); + return ComplaintRequest.endComplaintRequest(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/email-login-request.ts b/ui/src/gen/fbs/scrabblefb/email-login-request.ts new file mode 100644 index 0000000..c5e2332 --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/email-login-request.ts @@ -0,0 +1,60 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class EmailLoginRequest { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):EmailLoginRequest { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsEmailLoginRequest(bb:flatbuffers.ByteBuffer, obj?:EmailLoginRequest):EmailLoginRequest { + return (obj || new EmailLoginRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsEmailLoginRequest(bb:flatbuffers.ByteBuffer, obj?:EmailLoginRequest):EmailLoginRequest { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new EmailLoginRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +email():string|null +email(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +email(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +code():string|null +code(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +code(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +static startEmailLoginRequest(builder:flatbuffers.Builder) { + builder.startObject(2); +} + +static addEmail(builder:flatbuffers.Builder, emailOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, emailOffset, 0); +} + +static addCode(builder:flatbuffers.Builder, codeOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, codeOffset, 0); +} + +static endEmailLoginRequest(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createEmailLoginRequest(builder:flatbuffers.Builder, emailOffset:flatbuffers.Offset, codeOffset:flatbuffers.Offset):flatbuffers.Offset { + EmailLoginRequest.startEmailLoginRequest(builder); + EmailLoginRequest.addEmail(builder, emailOffset); + EmailLoginRequest.addCode(builder, codeOffset); + return EmailLoginRequest.endEmailLoginRequest(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/email-request-request.ts b/ui/src/gen/fbs/scrabblefb/email-request-request.ts new file mode 100644 index 0000000..73edb2d --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/email-request-request.ts @@ -0,0 +1,48 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class EmailRequestRequest { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):EmailRequestRequest { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsEmailRequestRequest(bb:flatbuffers.ByteBuffer, obj?:EmailRequestRequest):EmailRequestRequest { + return (obj || new EmailRequestRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsEmailRequestRequest(bb:flatbuffers.ByteBuffer, obj?:EmailRequestRequest):EmailRequestRequest { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new EmailRequestRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +email():string|null +email(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +email(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +static startEmailRequestRequest(builder:flatbuffers.Builder) { + builder.startObject(1); +} + +static addEmail(builder:flatbuffers.Builder, emailOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, emailOffset, 0); +} + +static endEmailRequestRequest(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createEmailRequestRequest(builder:flatbuffers.Builder, emailOffset:flatbuffers.Offset):flatbuffers.Offset { + EmailRequestRequest.startEmailRequestRequest(builder); + EmailRequestRequest.addEmail(builder, emailOffset); + return EmailRequestRequest.endEmailRequestRequest(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/enqueue-request.ts b/ui/src/gen/fbs/scrabblefb/enqueue-request.ts new file mode 100644 index 0000000..293bba3 --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/enqueue-request.ts @@ -0,0 +1,48 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class EnqueueRequest { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):EnqueueRequest { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsEnqueueRequest(bb:flatbuffers.ByteBuffer, obj?:EnqueueRequest):EnqueueRequest { + return (obj || new EnqueueRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsEnqueueRequest(bb:flatbuffers.ByteBuffer, obj?:EnqueueRequest):EnqueueRequest { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new EnqueueRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +variant():string|null +variant(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +variant(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +static startEnqueueRequest(builder:flatbuffers.Builder) { + builder.startObject(1); +} + +static addVariant(builder:flatbuffers.Builder, variantOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, variantOffset, 0); +} + +static endEnqueueRequest(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createEnqueueRequest(builder:flatbuffers.Builder, variantOffset:flatbuffers.Offset):flatbuffers.Offset { + EnqueueRequest.startEnqueueRequest(builder); + EnqueueRequest.addVariant(builder, variantOffset); + return EnqueueRequest.endEnqueueRequest(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/eval-request.ts b/ui/src/gen/fbs/scrabblefb/eval-request.ts new file mode 100644 index 0000000..1ddf0df --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/eval-request.ts @@ -0,0 +1,90 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +import { TileRecord } from '../scrabblefb/tile-record.js'; + + +export class EvalRequest { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):EvalRequest { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsEvalRequest(bb:flatbuffers.ByteBuffer, obj?:EvalRequest):EvalRequest { + return (obj || new EvalRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsEvalRequest(bb:flatbuffers.ByteBuffer, obj?:EvalRequest):EvalRequest { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new EvalRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +gameId():string|null +gameId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +gameId(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +dir():string|null +dir(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +dir(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +tiles(index: number, obj?:TileRecord):TileRecord|null { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? (obj || new TileRecord()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null; +} + +tilesLength():number { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; +} + +static startEvalRequest(builder:flatbuffers.Builder) { + builder.startObject(3); +} + +static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, gameIdOffset, 0); +} + +static addDir(builder:flatbuffers.Builder, dirOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, dirOffset, 0); +} + +static addTiles(builder:flatbuffers.Builder, tilesOffset:flatbuffers.Offset) { + builder.addFieldOffset(2, tilesOffset, 0); +} + +static createTilesVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); +} + +static startTilesVector(builder:flatbuffers.Builder, numElems:number) { + builder.startVector(4, numElems, 4); +} + +static endEvalRequest(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createEvalRequest(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset, dirOffset:flatbuffers.Offset, tilesOffset:flatbuffers.Offset):flatbuffers.Offset { + EvalRequest.startEvalRequest(builder); + EvalRequest.addGameId(builder, gameIdOffset); + EvalRequest.addDir(builder, dirOffset); + EvalRequest.addTiles(builder, tilesOffset); + return EvalRequest.endEvalRequest(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/eval-result.ts b/ui/src/gen/fbs/scrabblefb/eval-result.ts new file mode 100644 index 0000000..f8e9c4e --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/eval-result.ts @@ -0,0 +1,85 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class EvalResult { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):EvalResult { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsEvalResult(bb:flatbuffers.ByteBuffer, obj?:EvalResult):EvalResult { + return (obj || new EvalResult()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsEvalResult(bb:flatbuffers.ByteBuffer, obj?:EvalResult):EvalResult { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new EvalResult()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +legal():boolean { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false; +} + +score():number { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +} + +words(index: number):string +words(index: number,optionalEncoding:flatbuffers.Encoding):string|Uint8Array +words(index: number,optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.__string(this.bb!.__vector(this.bb_pos + offset) + index * 4, optionalEncoding) : null; +} + +wordsLength():number { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; +} + +static startEvalResult(builder:flatbuffers.Builder) { + builder.startObject(3); +} + +static addLegal(builder:flatbuffers.Builder, legal:boolean) { + builder.addFieldInt8(0, +legal, +false); +} + +static addScore(builder:flatbuffers.Builder, score:number) { + builder.addFieldInt32(1, score, 0); +} + +static addWords(builder:flatbuffers.Builder, wordsOffset:flatbuffers.Offset) { + builder.addFieldOffset(2, wordsOffset, 0); +} + +static createWordsVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); +} + +static startWordsVector(builder:flatbuffers.Builder, numElems:number) { + builder.startVector(4, numElems, 4); +} + +static endEvalResult(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createEvalResult(builder:flatbuffers.Builder, legal:boolean, score:number, wordsOffset:flatbuffers.Offset):flatbuffers.Offset { + EvalResult.startEvalResult(builder); + EvalResult.addLegal(builder, legal); + EvalResult.addScore(builder, score); + EvalResult.addWords(builder, wordsOffset); + return EvalResult.endEvalResult(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/exchange-request.ts b/ui/src/gen/fbs/scrabblefb/exchange-request.ts new file mode 100644 index 0000000..b13025d --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/exchange-request.ts @@ -0,0 +1,77 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class ExchangeRequest { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):ExchangeRequest { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsExchangeRequest(bb:flatbuffers.ByteBuffer, obj?:ExchangeRequest):ExchangeRequest { + return (obj || new ExchangeRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsExchangeRequest(bb:flatbuffers.ByteBuffer, obj?:ExchangeRequest):ExchangeRequest { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new ExchangeRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +gameId():string|null +gameId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +gameId(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +tiles(index: number):string +tiles(index: number,optionalEncoding:flatbuffers.Encoding):string|Uint8Array +tiles(index: number,optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__string(this.bb!.__vector(this.bb_pos + offset) + index * 4, optionalEncoding) : null; +} + +tilesLength():number { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; +} + +static startExchangeRequest(builder:flatbuffers.Builder) { + builder.startObject(2); +} + +static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, gameIdOffset, 0); +} + +static addTiles(builder:flatbuffers.Builder, tilesOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, tilesOffset, 0); +} + +static createTilesVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); +} + +static startTilesVector(builder:flatbuffers.Builder, numElems:number) { + builder.startVector(4, numElems, 4); +} + +static endExchangeRequest(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createExchangeRequest(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset, tilesOffset:flatbuffers.Offset):flatbuffers.Offset { + ExchangeRequest.startExchangeRequest(builder); + ExchangeRequest.addGameId(builder, gameIdOffset); + ExchangeRequest.addTiles(builder, tilesOffset); + return ExchangeRequest.endExchangeRequest(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/game-action-request.ts b/ui/src/gen/fbs/scrabblefb/game-action-request.ts new file mode 100644 index 0000000..b2687b4 --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/game-action-request.ts @@ -0,0 +1,48 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class GameActionRequest { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):GameActionRequest { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsGameActionRequest(bb:flatbuffers.ByteBuffer, obj?:GameActionRequest):GameActionRequest { + return (obj || new GameActionRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsGameActionRequest(bb:flatbuffers.ByteBuffer, obj?:GameActionRequest):GameActionRequest { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new GameActionRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +gameId():string|null +gameId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +gameId(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +static startGameActionRequest(builder:flatbuffers.Builder) { + builder.startObject(1); +} + +static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, gameIdOffset, 0); +} + +static endGameActionRequest(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createGameActionRequest(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset):flatbuffers.Offset { + GameActionRequest.startGameActionRequest(builder); + GameActionRequest.addGameId(builder, gameIdOffset); + return GameActionRequest.endGameActionRequest(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/game-list.ts b/ui/src/gen/fbs/scrabblefb/game-list.ts new file mode 100644 index 0000000..ff5b09a --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/game-list.ts @@ -0,0 +1,66 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +import { GameView } from '../scrabblefb/game-view.js'; + + +export class GameList { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):GameList { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsGameList(bb:flatbuffers.ByteBuffer, obj?:GameList):GameList { + return (obj || new GameList()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsGameList(bb:flatbuffers.ByteBuffer, obj?:GameList):GameList { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new GameList()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +games(index: number, obj?:GameView):GameView|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? (obj || new GameView()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null; +} + +gamesLength():number { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; +} + +static startGameList(builder:flatbuffers.Builder) { + builder.startObject(1); +} + +static addGames(builder:flatbuffers.Builder, gamesOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, gamesOffset, 0); +} + +static createGamesVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); +} + +static startGamesVector(builder:flatbuffers.Builder, numElems:number) { + builder.startVector(4, numElems, 4); +} + +static endGameList(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createGameList(builder:flatbuffers.Builder, gamesOffset:flatbuffers.Offset):flatbuffers.Offset { + GameList.startGameList(builder); + GameList.addGames(builder, gamesOffset); + return GameList.endGameList(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/game-view.ts b/ui/src/gen/fbs/scrabblefb/game-view.ts new file mode 100644 index 0000000..7e0f8e9 --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/game-view.ts @@ -0,0 +1,166 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +import { SeatView } from '../scrabblefb/seat-view.js'; + + +export class GameView { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):GameView { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsGameView(bb:flatbuffers.ByteBuffer, obj?:GameView):GameView { + return (obj || new GameView()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsGameView(bb:flatbuffers.ByteBuffer, obj?:GameView):GameView { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new GameView()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +id():string|null +id(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +id(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +variant():string|null +variant(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +variant(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +dictVersion():string|null +dictVersion(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +dictVersion(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +status():string|null +status(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +status(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 10); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +players():number { + const offset = this.bb!.__offset(this.bb_pos, 12); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +} + +toMove():number { + const offset = this.bb!.__offset(this.bb_pos, 14); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +} + +turnTimeoutSecs():number { + const offset = this.bb!.__offset(this.bb_pos, 16); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +} + +moveCount():number { + const offset = this.bb!.__offset(this.bb_pos, 18); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +} + +endReason():string|null +endReason(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +endReason(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 20); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +seats(index: number, obj?:SeatView):SeatView|null { + const offset = this.bb!.__offset(this.bb_pos, 22); + return offset ? (obj || new SeatView()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null; +} + +seatsLength():number { + const offset = this.bb!.__offset(this.bb_pos, 22); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; +} + +static startGameView(builder:flatbuffers.Builder) { + builder.startObject(10); +} + +static addId(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, idOffset, 0); +} + +static addVariant(builder:flatbuffers.Builder, variantOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, variantOffset, 0); +} + +static addDictVersion(builder:flatbuffers.Builder, dictVersionOffset:flatbuffers.Offset) { + builder.addFieldOffset(2, dictVersionOffset, 0); +} + +static addStatus(builder:flatbuffers.Builder, statusOffset:flatbuffers.Offset) { + builder.addFieldOffset(3, statusOffset, 0); +} + +static addPlayers(builder:flatbuffers.Builder, players:number) { + builder.addFieldInt32(4, players, 0); +} + +static addToMove(builder:flatbuffers.Builder, toMove:number) { + builder.addFieldInt32(5, toMove, 0); +} + +static addTurnTimeoutSecs(builder:flatbuffers.Builder, turnTimeoutSecs:number) { + builder.addFieldInt32(6, turnTimeoutSecs, 0); +} + +static addMoveCount(builder:flatbuffers.Builder, moveCount:number) { + builder.addFieldInt32(7, moveCount, 0); +} + +static addEndReason(builder:flatbuffers.Builder, endReasonOffset:flatbuffers.Offset) { + builder.addFieldOffset(8, endReasonOffset, 0); +} + +static addSeats(builder:flatbuffers.Builder, seatsOffset:flatbuffers.Offset) { + builder.addFieldOffset(9, seatsOffset, 0); +} + +static createSeatsVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); +} + +static startSeatsVector(builder:flatbuffers.Builder, numElems:number) { + builder.startVector(4, numElems, 4); +} + +static endGameView(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createGameView(builder:flatbuffers.Builder, idOffset:flatbuffers.Offset, variantOffset:flatbuffers.Offset, dictVersionOffset:flatbuffers.Offset, statusOffset:flatbuffers.Offset, players:number, toMove:number, turnTimeoutSecs:number, moveCount:number, endReasonOffset:flatbuffers.Offset, seatsOffset:flatbuffers.Offset):flatbuffers.Offset { + GameView.startGameView(builder); + GameView.addId(builder, idOffset); + GameView.addVariant(builder, variantOffset); + GameView.addDictVersion(builder, dictVersionOffset); + GameView.addStatus(builder, statusOffset); + GameView.addPlayers(builder, players); + GameView.addToMove(builder, toMove); + GameView.addTurnTimeoutSecs(builder, turnTimeoutSecs); + GameView.addMoveCount(builder, moveCount); + GameView.addEndReason(builder, endReasonOffset); + GameView.addSeats(builder, seatsOffset); + return GameView.endGameView(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/guest-login-request.ts b/ui/src/gen/fbs/scrabblefb/guest-login-request.ts new file mode 100644 index 0000000..ff46bdd --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/guest-login-request.ts @@ -0,0 +1,48 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class GuestLoginRequest { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):GuestLoginRequest { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsGuestLoginRequest(bb:flatbuffers.ByteBuffer, obj?:GuestLoginRequest):GuestLoginRequest { + return (obj || new GuestLoginRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsGuestLoginRequest(bb:flatbuffers.ByteBuffer, obj?:GuestLoginRequest):GuestLoginRequest { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new GuestLoginRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +locale():string|null +locale(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +locale(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +static startGuestLoginRequest(builder:flatbuffers.Builder) { + builder.startObject(1); +} + +static addLocale(builder:flatbuffers.Builder, localeOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, localeOffset, 0); +} + +static endGuestLoginRequest(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createGuestLoginRequest(builder:flatbuffers.Builder, localeOffset:flatbuffers.Offset):flatbuffers.Offset { + GuestLoginRequest.startGuestLoginRequest(builder); + GuestLoginRequest.addLocale(builder, localeOffset); + return GuestLoginRequest.endGuestLoginRequest(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/hint-result.ts b/ui/src/gen/fbs/scrabblefb/hint-result.ts new file mode 100644 index 0000000..511412f --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/hint-result.ts @@ -0,0 +1,59 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +import { MoveRecord } from '../scrabblefb/move-record.js'; + + +export class HintResult { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):HintResult { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsHintResult(bb:flatbuffers.ByteBuffer, obj?:HintResult):HintResult { + return (obj || new HintResult()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsHintResult(bb:flatbuffers.ByteBuffer, obj?:HintResult):HintResult { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new HintResult()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +move(obj?:MoveRecord):MoveRecord|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? (obj || new MoveRecord()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null; +} + +hintsRemaining():number { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +} + +static startHintResult(builder:flatbuffers.Builder) { + builder.startObject(2); +} + +static addMove(builder:flatbuffers.Builder, moveOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, moveOffset, 0); +} + +static addHintsRemaining(builder:flatbuffers.Builder, hintsRemaining:number) { + builder.addFieldInt32(1, hintsRemaining, 0); +} + +static endHintResult(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createHintResult(builder:flatbuffers.Builder, moveOffset:flatbuffers.Offset, hintsRemaining:number):flatbuffers.Offset { + HintResult.startHintResult(builder); + HintResult.addMove(builder, moveOffset); + HintResult.addHintsRemaining(builder, hintsRemaining); + return HintResult.endHintResult(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/history.ts b/ui/src/gen/fbs/scrabblefb/history.ts new file mode 100644 index 0000000..abc8003 --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/history.ts @@ -0,0 +1,78 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +import { MoveRecord } from '../scrabblefb/move-record.js'; + + +export class History { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):History { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsHistory(bb:flatbuffers.ByteBuffer, obj?:History):History { + return (obj || new History()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsHistory(bb:flatbuffers.ByteBuffer, obj?:History):History { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new History()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +gameId():string|null +gameId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +gameId(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +moves(index: number, obj?:MoveRecord):MoveRecord|null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? (obj || new MoveRecord()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null; +} + +movesLength():number { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; +} + +static startHistory(builder:flatbuffers.Builder) { + builder.startObject(2); +} + +static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, gameIdOffset, 0); +} + +static addMoves(builder:flatbuffers.Builder, movesOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, movesOffset, 0); +} + +static createMovesVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); +} + +static startMovesVector(builder:flatbuffers.Builder, numElems:number) { + builder.startVector(4, numElems, 4); +} + +static endHistory(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createHistory(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset, movesOffset:flatbuffers.Offset):flatbuffers.Offset { + History.startHistory(builder); + History.addGameId(builder, gameIdOffset); + History.addMoves(builder, movesOffset); + return History.endHistory(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/match-found-event.ts b/ui/src/gen/fbs/scrabblefb/match-found-event.ts new file mode 100644 index 0000000..8a0f9f7 --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/match-found-event.ts @@ -0,0 +1,48 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class MatchFoundEvent { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):MatchFoundEvent { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsMatchFoundEvent(bb:flatbuffers.ByteBuffer, obj?:MatchFoundEvent):MatchFoundEvent { + return (obj || new MatchFoundEvent()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsMatchFoundEvent(bb:flatbuffers.ByteBuffer, obj?:MatchFoundEvent):MatchFoundEvent { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new MatchFoundEvent()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +gameId():string|null +gameId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +gameId(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +static startMatchFoundEvent(builder:flatbuffers.Builder) { + builder.startObject(1); +} + +static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, gameIdOffset, 0); +} + +static endMatchFoundEvent(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createMatchFoundEvent(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset):flatbuffers.Offset { + MatchFoundEvent.startMatchFoundEvent(builder); + MatchFoundEvent.addGameId(builder, gameIdOffset); + return MatchFoundEvent.endMatchFoundEvent(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/match-result.ts b/ui/src/gen/fbs/scrabblefb/match-result.ts new file mode 100644 index 0000000..e0fb837 --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/match-result.ts @@ -0,0 +1,53 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +import { GameView } from '../scrabblefb/game-view.js'; + + +export class MatchResult { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):MatchResult { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsMatchResult(bb:flatbuffers.ByteBuffer, obj?:MatchResult):MatchResult { + return (obj || new MatchResult()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsMatchResult(bb:flatbuffers.ByteBuffer, obj?:MatchResult):MatchResult { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new MatchResult()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +matched():boolean { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false; +} + +game(obj?:GameView):GameView|null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? (obj || new GameView()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null; +} + +static startMatchResult(builder:flatbuffers.Builder) { + builder.startObject(2); +} + +static addMatched(builder:flatbuffers.Builder, matched:boolean) { + builder.addFieldInt8(0, +matched, +false); +} + +static addGame(builder:flatbuffers.Builder, gameOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, gameOffset, 0); +} + +static endMatchResult(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +} diff --git a/ui/src/gen/fbs/scrabblefb/move-record.ts b/ui/src/gen/fbs/scrabblefb/move-record.ts new file mode 100644 index 0000000..6329152 --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/move-record.ts @@ -0,0 +1,179 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +import { TileRecord } from '../scrabblefb/tile-record.js'; + + +export class MoveRecord { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):MoveRecord { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsMoveRecord(bb:flatbuffers.ByteBuffer, obj?:MoveRecord):MoveRecord { + return (obj || new MoveRecord()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsMoveRecord(bb:flatbuffers.ByteBuffer, obj?:MoveRecord):MoveRecord { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new MoveRecord()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +player():number { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +} + +action():string|null +action(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +action(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +dir():string|null +dir(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +dir(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +mainRow():number { + const offset = this.bb!.__offset(this.bb_pos, 10); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +} + +mainCol():number { + const offset = this.bb!.__offset(this.bb_pos, 12); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +} + +tiles(index: number, obj?:TileRecord):TileRecord|null { + const offset = this.bb!.__offset(this.bb_pos, 14); + return offset ? (obj || new TileRecord()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null; +} + +tilesLength():number { + const offset = this.bb!.__offset(this.bb_pos, 14); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; +} + +words(index: number):string +words(index: number,optionalEncoding:flatbuffers.Encoding):string|Uint8Array +words(index: number,optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 16); + return offset ? this.bb!.__string(this.bb!.__vector(this.bb_pos + offset) + index * 4, optionalEncoding) : null; +} + +wordsLength():number { + const offset = this.bb!.__offset(this.bb_pos, 16); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; +} + +count():number { + const offset = this.bb!.__offset(this.bb_pos, 18); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +} + +score():number { + const offset = this.bb!.__offset(this.bb_pos, 20); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +} + +total():number { + const offset = this.bb!.__offset(this.bb_pos, 22); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +} + +static startMoveRecord(builder:flatbuffers.Builder) { + builder.startObject(10); +} + +static addPlayer(builder:flatbuffers.Builder, player:number) { + builder.addFieldInt32(0, player, 0); +} + +static addAction(builder:flatbuffers.Builder, actionOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, actionOffset, 0); +} + +static addDir(builder:flatbuffers.Builder, dirOffset:flatbuffers.Offset) { + builder.addFieldOffset(2, dirOffset, 0); +} + +static addMainRow(builder:flatbuffers.Builder, mainRow:number) { + builder.addFieldInt32(3, mainRow, 0); +} + +static addMainCol(builder:flatbuffers.Builder, mainCol:number) { + builder.addFieldInt32(4, mainCol, 0); +} + +static addTiles(builder:flatbuffers.Builder, tilesOffset:flatbuffers.Offset) { + builder.addFieldOffset(5, tilesOffset, 0); +} + +static createTilesVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); +} + +static startTilesVector(builder:flatbuffers.Builder, numElems:number) { + builder.startVector(4, numElems, 4); +} + +static addWords(builder:flatbuffers.Builder, wordsOffset:flatbuffers.Offset) { + builder.addFieldOffset(6, wordsOffset, 0); +} + +static createWordsVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); +} + +static startWordsVector(builder:flatbuffers.Builder, numElems:number) { + builder.startVector(4, numElems, 4); +} + +static addCount(builder:flatbuffers.Builder, count:number) { + builder.addFieldInt32(7, count, 0); +} + +static addScore(builder:flatbuffers.Builder, score:number) { + builder.addFieldInt32(8, score, 0); +} + +static addTotal(builder:flatbuffers.Builder, total:number) { + builder.addFieldInt32(9, total, 0); +} + +static endMoveRecord(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createMoveRecord(builder:flatbuffers.Builder, player:number, actionOffset:flatbuffers.Offset, dirOffset:flatbuffers.Offset, mainRow:number, mainCol:number, tilesOffset:flatbuffers.Offset, wordsOffset:flatbuffers.Offset, count:number, score:number, total:number):flatbuffers.Offset { + MoveRecord.startMoveRecord(builder); + MoveRecord.addPlayer(builder, player); + MoveRecord.addAction(builder, actionOffset); + MoveRecord.addDir(builder, dirOffset); + MoveRecord.addMainRow(builder, mainRow); + MoveRecord.addMainCol(builder, mainCol); + MoveRecord.addTiles(builder, tilesOffset); + MoveRecord.addWords(builder, wordsOffset); + MoveRecord.addCount(builder, count); + MoveRecord.addScore(builder, score); + MoveRecord.addTotal(builder, total); + return MoveRecord.endMoveRecord(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/move-result.ts b/ui/src/gen/fbs/scrabblefb/move-result.ts new file mode 100644 index 0000000..623950e --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/move-result.ts @@ -0,0 +1,54 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +import { GameView } from '../scrabblefb/game-view.js'; +import { MoveRecord } from '../scrabblefb/move-record.js'; + + +export class MoveResult { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):MoveResult { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsMoveResult(bb:flatbuffers.ByteBuffer, obj?:MoveResult):MoveResult { + return (obj || new MoveResult()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsMoveResult(bb:flatbuffers.ByteBuffer, obj?:MoveResult):MoveResult { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new MoveResult()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +move(obj?:MoveRecord):MoveRecord|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? (obj || new MoveRecord()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null; +} + +game(obj?:GameView):GameView|null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? (obj || new GameView()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null; +} + +static startMoveResult(builder:flatbuffers.Builder) { + builder.startObject(2); +} + +static addMove(builder:flatbuffers.Builder, moveOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, moveOffset, 0); +} + +static addGame(builder:flatbuffers.Builder, gameOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, gameOffset, 0); +} + +static endMoveResult(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +} diff --git a/ui/src/gen/fbs/scrabblefb/nudge-event.ts b/ui/src/gen/fbs/scrabblefb/nudge-event.ts new file mode 100644 index 0000000..5673ab5 --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/nudge-event.ts @@ -0,0 +1,60 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class NudgeEvent { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):NudgeEvent { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsNudgeEvent(bb:flatbuffers.ByteBuffer, obj?:NudgeEvent):NudgeEvent { + return (obj || new NudgeEvent()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsNudgeEvent(bb:flatbuffers.ByteBuffer, obj?:NudgeEvent):NudgeEvent { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new NudgeEvent()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +gameId():string|null +gameId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +gameId(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +fromUserId():string|null +fromUserId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +fromUserId(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +static startNudgeEvent(builder:flatbuffers.Builder) { + builder.startObject(2); +} + +static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, gameIdOffset, 0); +} + +static addFromUserId(builder:flatbuffers.Builder, fromUserIdOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, fromUserIdOffset, 0); +} + +static endNudgeEvent(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createNudgeEvent(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset, fromUserIdOffset:flatbuffers.Offset):flatbuffers.Offset { + NudgeEvent.startNudgeEvent(builder); + NudgeEvent.addGameId(builder, gameIdOffset); + NudgeEvent.addFromUserId(builder, fromUserIdOffset); + return NudgeEvent.endNudgeEvent(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/opponent-moved-event.ts b/ui/src/gen/fbs/scrabblefb/opponent-moved-event.ts new file mode 100644 index 0000000..654a3fd --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/opponent-moved-event.ts @@ -0,0 +1,90 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class OpponentMovedEvent { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):OpponentMovedEvent { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsOpponentMovedEvent(bb:flatbuffers.ByteBuffer, obj?:OpponentMovedEvent):OpponentMovedEvent { + return (obj || new OpponentMovedEvent()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsOpponentMovedEvent(bb:flatbuffers.ByteBuffer, obj?:OpponentMovedEvent):OpponentMovedEvent { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new OpponentMovedEvent()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +gameId():string|null +gameId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +gameId(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +seat():number { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +} + +action():string|null +action(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +action(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +score():number { + const offset = this.bb!.__offset(this.bb_pos, 10); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +} + +total():number { + const offset = this.bb!.__offset(this.bb_pos, 12); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +} + +static startOpponentMovedEvent(builder:flatbuffers.Builder) { + builder.startObject(5); +} + +static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, gameIdOffset, 0); +} + +static addSeat(builder:flatbuffers.Builder, seat:number) { + builder.addFieldInt32(1, seat, 0); +} + +static addAction(builder:flatbuffers.Builder, actionOffset:flatbuffers.Offset) { + builder.addFieldOffset(2, actionOffset, 0); +} + +static addScore(builder:flatbuffers.Builder, score:number) { + builder.addFieldInt32(3, score, 0); +} + +static addTotal(builder:flatbuffers.Builder, total:number) { + builder.addFieldInt32(4, total, 0); +} + +static endOpponentMovedEvent(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createOpponentMovedEvent(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset, seat:number, actionOffset:flatbuffers.Offset, score:number, total:number):flatbuffers.Offset { + OpponentMovedEvent.startOpponentMovedEvent(builder); + OpponentMovedEvent.addGameId(builder, gameIdOffset); + OpponentMovedEvent.addSeat(builder, seat); + OpponentMovedEvent.addAction(builder, actionOffset); + OpponentMovedEvent.addScore(builder, score); + OpponentMovedEvent.addTotal(builder, total); + return OpponentMovedEvent.endOpponentMovedEvent(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/profile.ts b/ui/src/gen/fbs/scrabblefb/profile.ts new file mode 100644 index 0000000..f70e192 --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/profile.ts @@ -0,0 +1,124 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class Profile { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):Profile { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsProfile(bb:flatbuffers.ByteBuffer, obj?:Profile):Profile { + return (obj || new Profile()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsProfile(bb:flatbuffers.ByteBuffer, obj?:Profile):Profile { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new Profile()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +userId():string|null +userId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +userId(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +displayName():string|null +displayName(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +displayName(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +preferredLanguage():string|null +preferredLanguage(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +preferredLanguage(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +timeZone():string|null +timeZone(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +timeZone(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 10); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +hintBalance():number { + const offset = this.bb!.__offset(this.bb_pos, 12); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +} + +blockChat():boolean { + const offset = this.bb!.__offset(this.bb_pos, 14); + return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false; +} + +blockFriendRequests():boolean { + const offset = this.bb!.__offset(this.bb_pos, 16); + return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false; +} + +isGuest():boolean { + const offset = this.bb!.__offset(this.bb_pos, 18); + return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false; +} + +static startProfile(builder:flatbuffers.Builder) { + builder.startObject(8); +} + +static addUserId(builder:flatbuffers.Builder, userIdOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, userIdOffset, 0); +} + +static addDisplayName(builder:flatbuffers.Builder, displayNameOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, displayNameOffset, 0); +} + +static addPreferredLanguage(builder:flatbuffers.Builder, preferredLanguageOffset:flatbuffers.Offset) { + builder.addFieldOffset(2, preferredLanguageOffset, 0); +} + +static addTimeZone(builder:flatbuffers.Builder, timeZoneOffset:flatbuffers.Offset) { + builder.addFieldOffset(3, timeZoneOffset, 0); +} + +static addHintBalance(builder:flatbuffers.Builder, hintBalance:number) { + builder.addFieldInt32(4, hintBalance, 0); +} + +static addBlockChat(builder:flatbuffers.Builder, blockChat:boolean) { + builder.addFieldInt8(5, +blockChat, +false); +} + +static addBlockFriendRequests(builder:flatbuffers.Builder, blockFriendRequests:boolean) { + builder.addFieldInt8(6, +blockFriendRequests, +false); +} + +static addIsGuest(builder:flatbuffers.Builder, isGuest:boolean) { + builder.addFieldInt8(7, +isGuest, +false); +} + +static endProfile(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createProfile(builder:flatbuffers.Builder, userIdOffset:flatbuffers.Offset, displayNameOffset:flatbuffers.Offset, preferredLanguageOffset:flatbuffers.Offset, timeZoneOffset:flatbuffers.Offset, hintBalance:number, blockChat:boolean, blockFriendRequests:boolean, isGuest:boolean):flatbuffers.Offset { + Profile.startProfile(builder); + Profile.addUserId(builder, userIdOffset); + Profile.addDisplayName(builder, displayNameOffset); + Profile.addPreferredLanguage(builder, preferredLanguageOffset); + Profile.addTimeZone(builder, timeZoneOffset); + Profile.addHintBalance(builder, hintBalance); + Profile.addBlockChat(builder, blockChat); + Profile.addBlockFriendRequests(builder, blockFriendRequests); + Profile.addIsGuest(builder, isGuest); + return Profile.endProfile(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/seat-view.ts b/ui/src/gen/fbs/scrabblefb/seat-view.ts new file mode 100644 index 0000000..9d253be --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/seat-view.ts @@ -0,0 +1,100 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class SeatView { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):SeatView { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsSeatView(bb:flatbuffers.ByteBuffer, obj?:SeatView):SeatView { + return (obj || new SeatView()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsSeatView(bb:flatbuffers.ByteBuffer, obj?:SeatView):SeatView { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new SeatView()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +seat():number { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +} + +accountId():string|null +accountId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +accountId(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +score():number { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +} + +hintsUsed():number { + const offset = this.bb!.__offset(this.bb_pos, 10); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +} + +isWinner():boolean { + const offset = this.bb!.__offset(this.bb_pos, 12); + return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false; +} + +displayName():string|null +displayName(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +displayName(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 14); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +static startSeatView(builder:flatbuffers.Builder) { + builder.startObject(6); +} + +static addSeat(builder:flatbuffers.Builder, seat:number) { + builder.addFieldInt32(0, seat, 0); +} + +static addAccountId(builder:flatbuffers.Builder, accountIdOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, accountIdOffset, 0); +} + +static addScore(builder:flatbuffers.Builder, score:number) { + builder.addFieldInt32(2, score, 0); +} + +static addHintsUsed(builder:flatbuffers.Builder, hintsUsed:number) { + builder.addFieldInt32(3, hintsUsed, 0); +} + +static addIsWinner(builder:flatbuffers.Builder, isWinner:boolean) { + builder.addFieldInt8(4, +isWinner, +false); +} + +static addDisplayName(builder:flatbuffers.Builder, displayNameOffset:flatbuffers.Offset) { + builder.addFieldOffset(5, displayNameOffset, 0); +} + +static endSeatView(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createSeatView(builder:flatbuffers.Builder, seat:number, accountIdOffset:flatbuffers.Offset, score:number, hintsUsed:number, isWinner:boolean, displayNameOffset:flatbuffers.Offset):flatbuffers.Offset { + SeatView.startSeatView(builder); + SeatView.addSeat(builder, seat); + SeatView.addAccountId(builder, accountIdOffset); + SeatView.addScore(builder, score); + SeatView.addHintsUsed(builder, hintsUsed); + SeatView.addIsWinner(builder, isWinner); + SeatView.addDisplayName(builder, displayNameOffset); + return SeatView.endSeatView(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/session.ts b/ui/src/gen/fbs/scrabblefb/session.ts new file mode 100644 index 0000000..6882465 --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/session.ts @@ -0,0 +1,82 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class Session { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):Session { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsSession(bb:flatbuffers.ByteBuffer, obj?:Session):Session { + return (obj || new Session()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsSession(bb:flatbuffers.ByteBuffer, obj?:Session):Session { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new Session()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +token():string|null +token(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +token(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +userId():string|null +userId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +userId(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +isGuest():boolean { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false; +} + +displayName():string|null +displayName(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +displayName(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 10); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +static startSession(builder:flatbuffers.Builder) { + builder.startObject(4); +} + +static addToken(builder:flatbuffers.Builder, tokenOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, tokenOffset, 0); +} + +static addUserId(builder:flatbuffers.Builder, userIdOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, userIdOffset, 0); +} + +static addIsGuest(builder:flatbuffers.Builder, isGuest:boolean) { + builder.addFieldInt8(2, +isGuest, +false); +} + +static addDisplayName(builder:flatbuffers.Builder, displayNameOffset:flatbuffers.Offset) { + builder.addFieldOffset(3, displayNameOffset, 0); +} + +static endSession(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createSession(builder:flatbuffers.Builder, tokenOffset:flatbuffers.Offset, userIdOffset:flatbuffers.Offset, isGuest:boolean, displayNameOffset:flatbuffers.Offset):flatbuffers.Offset { + Session.startSession(builder); + Session.addToken(builder, tokenOffset); + Session.addUserId(builder, userIdOffset); + Session.addIsGuest(builder, isGuest); + Session.addDisplayName(builder, displayNameOffset); + return Session.endSession(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/state-request.ts b/ui/src/gen/fbs/scrabblefb/state-request.ts new file mode 100644 index 0000000..84c37a9 --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/state-request.ts @@ -0,0 +1,48 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class StateRequest { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):StateRequest { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsStateRequest(bb:flatbuffers.ByteBuffer, obj?:StateRequest):StateRequest { + return (obj || new StateRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsStateRequest(bb:flatbuffers.ByteBuffer, obj?:StateRequest):StateRequest { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new StateRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +gameId():string|null +gameId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +gameId(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +static startStateRequest(builder:flatbuffers.Builder) { + builder.startObject(1); +} + +static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, gameIdOffset, 0); +} + +static endStateRequest(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createStateRequest(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset):flatbuffers.Offset { + StateRequest.startStateRequest(builder); + StateRequest.addGameId(builder, gameIdOffset); + return StateRequest.endStateRequest(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/state-view.ts b/ui/src/gen/fbs/scrabblefb/state-view.ts new file mode 100644 index 0000000..3f944ea --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/state-view.ts @@ -0,0 +1,108 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +import { GameView } from '../scrabblefb/game-view.js'; + + +export class StateView { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):StateView { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsStateView(bb:flatbuffers.ByteBuffer, obj?:StateView):StateView { + return (obj || new StateView()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsStateView(bb:flatbuffers.ByteBuffer, obj?:StateView):StateView { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new StateView()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +game(obj?:GameView):GameView|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? (obj || new GameView()).__init(this.bb!.__indirect(this.bb_pos + offset), this.bb!) : null; +} + +seat():number { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +} + +rack(index: number):string +rack(index: number,optionalEncoding:flatbuffers.Encoding):string|Uint8Array +rack(index: number,optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.__string(this.bb!.__vector(this.bb_pos + offset) + index * 4, optionalEncoding) : null; +} + +rackLength():number { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; +} + +bagLen():number { + const offset = this.bb!.__offset(this.bb_pos, 10); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +} + +hintsRemaining():number { + const offset = this.bb!.__offset(this.bb_pos, 12); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +} + +static startStateView(builder:flatbuffers.Builder) { + builder.startObject(5); +} + +static addGame(builder:flatbuffers.Builder, gameOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, gameOffset, 0); +} + +static addSeat(builder:flatbuffers.Builder, seat:number) { + builder.addFieldInt32(1, seat, 0); +} + +static addRack(builder:flatbuffers.Builder, rackOffset:flatbuffers.Offset) { + builder.addFieldOffset(2, rackOffset, 0); +} + +static createRackVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); +} + +static startRackVector(builder:flatbuffers.Builder, numElems:number) { + builder.startVector(4, numElems, 4); +} + +static addBagLen(builder:flatbuffers.Builder, bagLen:number) { + builder.addFieldInt32(3, bagLen, 0); +} + +static addHintsRemaining(builder:flatbuffers.Builder, hintsRemaining:number) { + builder.addFieldInt32(4, hintsRemaining, 0); +} + +static endStateView(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createStateView(builder:flatbuffers.Builder, gameOffset:flatbuffers.Offset, seat:number, rackOffset:flatbuffers.Offset, bagLen:number, hintsRemaining:number):flatbuffers.Offset { + StateView.startStateView(builder); + StateView.addGame(builder, gameOffset); + StateView.addSeat(builder, seat); + StateView.addRack(builder, rackOffset); + StateView.addBagLen(builder, bagLen); + StateView.addHintsRemaining(builder, hintsRemaining); + return StateView.endStateView(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/submit-play-request.ts b/ui/src/gen/fbs/scrabblefb/submit-play-request.ts new file mode 100644 index 0000000..c18543f --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/submit-play-request.ts @@ -0,0 +1,90 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +import { TileRecord } from '../scrabblefb/tile-record.js'; + + +export class SubmitPlayRequest { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):SubmitPlayRequest { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsSubmitPlayRequest(bb:flatbuffers.ByteBuffer, obj?:SubmitPlayRequest):SubmitPlayRequest { + return (obj || new SubmitPlayRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsSubmitPlayRequest(bb:flatbuffers.ByteBuffer, obj?:SubmitPlayRequest):SubmitPlayRequest { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new SubmitPlayRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +gameId():string|null +gameId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +gameId(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +dir():string|null +dir(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +dir(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +tiles(index: number, obj?:TileRecord):TileRecord|null { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? (obj || new TileRecord()).__init(this.bb!.__indirect(this.bb!.__vector(this.bb_pos + offset) + index * 4), this.bb!) : null; +} + +tilesLength():number { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.__vector_len(this.bb_pos + offset) : 0; +} + +static startSubmitPlayRequest(builder:flatbuffers.Builder) { + builder.startObject(3); +} + +static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, gameIdOffset, 0); +} + +static addDir(builder:flatbuffers.Builder, dirOffset:flatbuffers.Offset) { + builder.addFieldOffset(1, dirOffset, 0); +} + +static addTiles(builder:flatbuffers.Builder, tilesOffset:flatbuffers.Offset) { + builder.addFieldOffset(2, tilesOffset, 0); +} + +static createTilesVector(builder:flatbuffers.Builder, data:flatbuffers.Offset[]):flatbuffers.Offset { + builder.startVector(4, data.length, 4); + for (let i = data.length - 1; i >= 0; i--) { + builder.addOffset(data[i]!); + } + return builder.endVector(); +} + +static startTilesVector(builder:flatbuffers.Builder, numElems:number) { + builder.startVector(4, numElems, 4); +} + +static endSubmitPlayRequest(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createSubmitPlayRequest(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset, dirOffset:flatbuffers.Offset, tilesOffset:flatbuffers.Offset):flatbuffers.Offset { + SubmitPlayRequest.startSubmitPlayRequest(builder); + SubmitPlayRequest.addGameId(builder, gameIdOffset); + SubmitPlayRequest.addDir(builder, dirOffset); + SubmitPlayRequest.addTiles(builder, tilesOffset); + return SubmitPlayRequest.endSubmitPlayRequest(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/telegram-login-request.ts b/ui/src/gen/fbs/scrabblefb/telegram-login-request.ts new file mode 100644 index 0000000..47ba75f --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/telegram-login-request.ts @@ -0,0 +1,48 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class TelegramLoginRequest { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):TelegramLoginRequest { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsTelegramLoginRequest(bb:flatbuffers.ByteBuffer, obj?:TelegramLoginRequest):TelegramLoginRequest { + return (obj || new TelegramLoginRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsTelegramLoginRequest(bb:flatbuffers.ByteBuffer, obj?:TelegramLoginRequest):TelegramLoginRequest { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new TelegramLoginRequest()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +initData():string|null +initData(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +initData(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +static startTelegramLoginRequest(builder:flatbuffers.Builder) { + builder.startObject(1); +} + +static addInitData(builder:flatbuffers.Builder, initDataOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, initDataOffset, 0); +} + +static endTelegramLoginRequest(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createTelegramLoginRequest(builder:flatbuffers.Builder, initDataOffset:flatbuffers.Offset):flatbuffers.Offset { + TelegramLoginRequest.startTelegramLoginRequest(builder); + TelegramLoginRequest.addInitData(builder, initDataOffset); + return TelegramLoginRequest.endTelegramLoginRequest(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/tile-record.ts b/ui/src/gen/fbs/scrabblefb/tile-record.ts new file mode 100644 index 0000000..56e4115 --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/tile-record.ts @@ -0,0 +1,78 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class TileRecord { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):TileRecord { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsTileRecord(bb:flatbuffers.ByteBuffer, obj?:TileRecord):TileRecord { + return (obj || new TileRecord()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsTileRecord(bb:flatbuffers.ByteBuffer, obj?:TileRecord):TileRecord { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new TileRecord()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +row():number { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +} + +col():number { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.readInt32(this.bb_pos + offset) : 0; +} + +letter():string|null +letter(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +letter(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 8); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +blank():boolean { + const offset = this.bb!.__offset(this.bb_pos, 10); + return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false; +} + +static startTileRecord(builder:flatbuffers.Builder) { + builder.startObject(4); +} + +static addRow(builder:flatbuffers.Builder, row:number) { + builder.addFieldInt32(0, row, 0); +} + +static addCol(builder:flatbuffers.Builder, col:number) { + builder.addFieldInt32(1, col, 0); +} + +static addLetter(builder:flatbuffers.Builder, letterOffset:flatbuffers.Offset) { + builder.addFieldOffset(2, letterOffset, 0); +} + +static addBlank(builder:flatbuffers.Builder, blank:boolean) { + builder.addFieldInt8(3, +blank, +false); +} + +static endTileRecord(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createTileRecord(builder:flatbuffers.Builder, row:number, col:number, letterOffset:flatbuffers.Offset, blank:boolean):flatbuffers.Offset { + TileRecord.startTileRecord(builder); + TileRecord.addRow(builder, row); + TileRecord.addCol(builder, col); + TileRecord.addLetter(builder, letterOffset); + TileRecord.addBlank(builder, blank); + return TileRecord.endTileRecord(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/word-check-result.ts b/ui/src/gen/fbs/scrabblefb/word-check-result.ts new file mode 100644 index 0000000..c750c9b --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/word-check-result.ts @@ -0,0 +1,58 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class WordCheckResult { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):WordCheckResult { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsWordCheckResult(bb:flatbuffers.ByteBuffer, obj?:WordCheckResult):WordCheckResult { + return (obj || new WordCheckResult()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsWordCheckResult(bb:flatbuffers.ByteBuffer, obj?:WordCheckResult):WordCheckResult { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new WordCheckResult()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +word():string|null +word(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +word(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +legal():boolean { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? !!this.bb!.readInt8(this.bb_pos + offset) : false; +} + +static startWordCheckResult(builder:flatbuffers.Builder) { + builder.startObject(2); +} + +static addWord(builder:flatbuffers.Builder, wordOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, wordOffset, 0); +} + +static addLegal(builder:flatbuffers.Builder, legal:boolean) { + builder.addFieldInt8(1, +legal, +false); +} + +static endWordCheckResult(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createWordCheckResult(builder:flatbuffers.Builder, wordOffset:flatbuffers.Offset, legal:boolean):flatbuffers.Offset { + WordCheckResult.startWordCheckResult(builder); + WordCheckResult.addWord(builder, wordOffset); + WordCheckResult.addLegal(builder, legal); + return WordCheckResult.endWordCheckResult(builder); +} +} diff --git a/ui/src/gen/fbs/scrabblefb/your-turn-event.ts b/ui/src/gen/fbs/scrabblefb/your-turn-event.ts new file mode 100644 index 0000000..360fb1d --- /dev/null +++ b/ui/src/gen/fbs/scrabblefb/your-turn-event.ts @@ -0,0 +1,58 @@ +// automatically generated by the FlatBuffers compiler, do not modify + +import * as flatbuffers from 'flatbuffers'; + +export class YourTurnEvent { + bb: flatbuffers.ByteBuffer|null = null; + bb_pos = 0; + __init(i:number, bb:flatbuffers.ByteBuffer):YourTurnEvent { + this.bb_pos = i; + this.bb = bb; + return this; +} + +static getRootAsYourTurnEvent(bb:flatbuffers.ByteBuffer, obj?:YourTurnEvent):YourTurnEvent { + return (obj || new YourTurnEvent()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +static getSizePrefixedRootAsYourTurnEvent(bb:flatbuffers.ByteBuffer, obj?:YourTurnEvent):YourTurnEvent { + bb.setPosition(bb.position() + flatbuffers.SIZE_PREFIX_LENGTH); + return (obj || new YourTurnEvent()).__init(bb.readInt32(bb.position()) + bb.position(), bb); +} + +gameId():string|null +gameId(optionalEncoding:flatbuffers.Encoding):string|Uint8Array|null +gameId(optionalEncoding?:any):string|Uint8Array|null { + const offset = this.bb!.__offset(this.bb_pos, 4); + return offset ? this.bb!.__string(this.bb_pos + offset, optionalEncoding) : null; +} + +deadlineUnix():bigint { + const offset = this.bb!.__offset(this.bb_pos, 6); + return offset ? this.bb!.readInt64(this.bb_pos + offset) : BigInt('0'); +} + +static startYourTurnEvent(builder:flatbuffers.Builder) { + builder.startObject(2); +} + +static addGameId(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset) { + builder.addFieldOffset(0, gameIdOffset, 0); +} + +static addDeadlineUnix(builder:flatbuffers.Builder, deadlineUnix:bigint) { + builder.addFieldInt64(1, deadlineUnix, BigInt('0')); +} + +static endYourTurnEvent(builder:flatbuffers.Builder):flatbuffers.Offset { + const offset = builder.endObject(); + return offset; +} + +static createYourTurnEvent(builder:flatbuffers.Builder, gameIdOffset:flatbuffers.Offset, deadlineUnix:bigint):flatbuffers.Offset { + YourTurnEvent.startYourTurnEvent(builder); + YourTurnEvent.addGameId(builder, gameIdOffset); + YourTurnEvent.addDeadlineUnix(builder, deadlineUnix); + return YourTurnEvent.endYourTurnEvent(builder); +} +} diff --git a/ui/src/lib/codec.ts b/ui/src/lib/codec.ts new file mode 100644 index 0000000..383b846 --- /dev/null +++ b/ui/src/lib/codec.ts @@ -0,0 +1,384 @@ +// FlatBuffers <-> domain-model codec. The real transport encodes each request table +// and decodes each response/event table here, mirroring the gateway's Go encoders in +// reverse. The screens only ever see the plain model (lib/model), never these wire +// types. + +import { Builder, ByteBuffer, type Offset } from 'flatbuffers'; +import * as fb from '../gen/fbs/scrabblefb'; +import type { PlacedTile } from './client'; +import type { + ChatMessage, + EvalResult, + GameList, + GameView, + History, + HintResult, + MatchResult, + MoveRecord, + MoveResult, + Profile, + PushEvent, + Seat, + Session, + StateView, + Tile, + Variant, + WordCheckResult, +} from './model'; + +// --- request encoders --- + +function buildTile(b: Builder, t: PlacedTile): Offset { + const letter = b.createString(t.letter); + fb.TileRecord.startTileRecord(b); + fb.TileRecord.addRow(b, t.row); + fb.TileRecord.addCol(b, t.col); + fb.TileRecord.addLetter(b, letter); + fb.TileRecord.addBlank(b, t.blank); + return fb.TileRecord.endTileRecord(b); +} + +function finish(b: Builder, root: Offset): Uint8Array { + b.finish(root); + return b.asUint8Array(); +} + +export const empty = (): Uint8Array => new Uint8Array(); + +export function encodeGameAction(gameId: string): Uint8Array { + const b = new Builder(64); + const gid = b.createString(gameId); + fb.GameActionRequest.startGameActionRequest(b); + fb.GameActionRequest.addGameId(b, gid); + return finish(b, fb.GameActionRequest.endGameActionRequest(b)); +} + +export function encodeStateRequest(gameId: string): Uint8Array { + const b = new Builder(64); + const gid = b.createString(gameId); + fb.StateRequest.startStateRequest(b); + fb.StateRequest.addGameId(b, gid); + return finish(b, fb.StateRequest.endStateRequest(b)); +} + +export function encodeSubmitPlay(gameId: string, dir: 'H' | 'V', tiles: PlacedTile[]): Uint8Array { + const b = new Builder(256); + const tileOffs = tiles.map((t) => buildTile(b, t)); + const vec = fb.SubmitPlayRequest.createTilesVector(b, tileOffs); + const gid = b.createString(gameId); + const d = b.createString(dir); + fb.SubmitPlayRequest.startSubmitPlayRequest(b); + fb.SubmitPlayRequest.addGameId(b, gid); + fb.SubmitPlayRequest.addDir(b, d); + fb.SubmitPlayRequest.addTiles(b, vec); + return finish(b, fb.SubmitPlayRequest.endSubmitPlayRequest(b)); +} + +export function encodeEval(gameId: string, dir: 'H' | 'V', tiles: PlacedTile[]): Uint8Array { + const b = new Builder(256); + const tileOffs = tiles.map((t) => buildTile(b, t)); + const vec = fb.EvalRequest.createTilesVector(b, tileOffs); + const gid = b.createString(gameId); + const d = b.createString(dir); + fb.EvalRequest.startEvalRequest(b); + fb.EvalRequest.addGameId(b, gid); + fb.EvalRequest.addDir(b, d); + fb.EvalRequest.addTiles(b, vec); + return finish(b, fb.EvalRequest.endEvalRequest(b)); +} + +export function encodeExchange(gameId: string, tiles: string[]): Uint8Array { + const b = new Builder(128); + const offs = tiles.map((s) => b.createString(s)); + const vec = fb.ExchangeRequest.createTilesVector(b, offs); + const gid = b.createString(gameId); + fb.ExchangeRequest.startExchangeRequest(b); + fb.ExchangeRequest.addGameId(b, gid); + fb.ExchangeRequest.addTiles(b, vec); + return finish(b, fb.ExchangeRequest.endExchangeRequest(b)); +} + +export function encodeCheckWord(gameId: string, word: string): Uint8Array { + const b = new Builder(128); + const gid = b.createString(gameId); + const w = b.createString(word); + fb.CheckWordRequest.startCheckWordRequest(b); + fb.CheckWordRequest.addGameId(b, gid); + fb.CheckWordRequest.addWord(b, w); + return finish(b, fb.CheckWordRequest.endCheckWordRequest(b)); +} + +export function encodeComplaint(gameId: string, word: string, note: string): Uint8Array { + const b = new Builder(256); + const gid = b.createString(gameId); + const w = b.createString(word); + const n = b.createString(note); + fb.ComplaintRequest.startComplaintRequest(b); + fb.ComplaintRequest.addGameId(b, gid); + fb.ComplaintRequest.addWord(b, w); + fb.ComplaintRequest.addNote(b, n); + return finish(b, fb.ComplaintRequest.endComplaintRequest(b)); +} + +export function encodeEnqueue(variant: Variant): Uint8Array { + const b = new Builder(64); + const v = b.createString(variant); + fb.EnqueueRequest.startEnqueueRequest(b); + fb.EnqueueRequest.addVariant(b, v); + return finish(b, fb.EnqueueRequest.endEnqueueRequest(b)); +} + +export function encodeChatPost(gameId: string, body: string): Uint8Array { + const b = new Builder(128); + const gid = b.createString(gameId); + const bd = b.createString(body); + fb.ChatPostRequest.startChatPostRequest(b); + fb.ChatPostRequest.addGameId(b, gid); + fb.ChatPostRequest.addBody(b, bd); + return finish(b, fb.ChatPostRequest.endChatPostRequest(b)); +} + +export function encodeGuestLogin(locale: string): Uint8Array { + const b = new Builder(64); + const l = b.createString(locale); + fb.GuestLoginRequest.startGuestLoginRequest(b); + fb.GuestLoginRequest.addLocale(b, l); + return finish(b, fb.GuestLoginRequest.endGuestLoginRequest(b)); +} + +export function encodeEmailRequest(email: string): Uint8Array { + const b = new Builder(128); + const e = b.createString(email); + fb.EmailRequestRequest.startEmailRequestRequest(b); + fb.EmailRequestRequest.addEmail(b, e); + return finish(b, fb.EmailRequestRequest.endEmailRequestRequest(b)); +} + +export function encodeEmailLogin(email: string, code: string): Uint8Array { + const b = new Builder(128); + const e = b.createString(email); + const c = b.createString(code); + fb.EmailLoginRequest.startEmailLoginRequest(b); + fb.EmailLoginRequest.addEmail(b, e); + fb.EmailLoginRequest.addCode(b, c); + return finish(b, fb.EmailLoginRequest.endEmailLoginRequest(b)); +} + +// --- response decoders --- + +function s(v: string | null): string { + return v ?? ''; +} + +function decodeTile(t: fb.TileRecord): Tile { + return { row: t.row(), col: t.col(), letter: s(t.letter()), blank: t.blank() }; +} + +function decodeSeat(v: fb.SeatView): Seat { + return { + seat: v.seat(), + accountId: s(v.accountId()), + displayName: s(v.displayName()), + score: v.score(), + hintsUsed: v.hintsUsed(), + isWinner: v.isWinner(), + }; +} + +function decodeGameView(g: fb.GameView): GameView { + const seats: Seat[] = []; + for (let i = 0; i < g.seatsLength(); i++) { + const sv = g.seats(i); + if (sv) seats.push(decodeSeat(sv)); + } + return { + id: s(g.id()), + variant: s(g.variant()) as Variant, + dictVersion: s(g.dictVersion()), + status: s(g.status()), + players: g.players(), + toMove: g.toMove(), + turnTimeoutSecs: g.turnTimeoutSecs(), + moveCount: g.moveCount(), + endReason: s(g.endReason()), + seats, + }; +} + +function decodeMove(m: fb.MoveRecord): MoveRecord { + const tiles: Tile[] = []; + for (let i = 0; i < m.tilesLength(); i++) { + const t = m.tiles(i); + if (t) tiles.push(decodeTile(t)); + } + const words: string[] = []; + for (let i = 0; i < m.wordsLength(); i++) words.push(s(m.words(i))); + return { + player: m.player(), + action: s(m.action()), + dir: s(m.dir()), + mainRow: m.mainRow(), + mainCol: m.mainCol(), + tiles, + words, + count: m.count(), + score: m.score(), + total: m.total(), + }; +} + +function decodeChatMsg(m: fb.ChatMessage): ChatMessage { + return { + id: s(m.id()), + gameId: s(m.gameId()), + senderId: s(m.senderId()), + kind: s(m.kind()), + body: s(m.body()), + createdAtUnix: Number(m.createdAtUnix()), + }; +} + +export function decodeSession(buf: Uint8Array): Session { + const t = fb.Session.getRootAsSession(new ByteBuffer(buf)); + return { token: s(t.token()), userId: s(t.userId()), isGuest: t.isGuest(), displayName: s(t.displayName()) }; +} + +export function decodeProfile(buf: Uint8Array): Profile { + const p = fb.Profile.getRootAsProfile(new ByteBuffer(buf)); + return { + userId: s(p.userId()), + displayName: s(p.displayName()), + preferredLanguage: s(p.preferredLanguage()), + timeZone: s(p.timeZone()), + hintBalance: p.hintBalance(), + blockChat: p.blockChat(), + blockFriendRequests: p.blockFriendRequests(), + isGuest: p.isGuest(), + }; +} + +export function decodeStateView(buf: Uint8Array): StateView { + const v = fb.StateView.getRootAsStateView(new ByteBuffer(buf)); + const g = v.game(); + const rack: string[] = []; + for (let i = 0; i < v.rackLength(); i++) rack.push(s(v.rack(i))); + return { + game: g ? decodeGameView(g) : emptyGame(), + seat: v.seat(), + rack, + bagLen: v.bagLen(), + hintsRemaining: v.hintsRemaining(), + }; +} + +export function decodeMoveResult(buf: Uint8Array): MoveResult { + const r = fb.MoveResult.getRootAsMoveResult(new ByteBuffer(buf)); + const m = r.move(); + const g = r.game(); + return { move: m ? decodeMove(m) : emptyMove(), game: g ? decodeGameView(g) : emptyGame() }; +} + +export function decodeHintResult(buf: Uint8Array): HintResult { + const r = fb.HintResult.getRootAsHintResult(new ByteBuffer(buf)); + const m = r.move(); + return { move: m ? decodeMove(m) : emptyMove(), hintsRemaining: r.hintsRemaining() }; +} + +export function decodeEvalResult(buf: Uint8Array): EvalResult { + const r = fb.EvalResult.getRootAsEvalResult(new ByteBuffer(buf)); + const words: string[] = []; + for (let i = 0; i < r.wordsLength(); i++) words.push(s(r.words(i))); + return { legal: r.legal(), score: r.score(), words }; +} + +export function decodeWordCheck(buf: Uint8Array): WordCheckResult { + const r = fb.WordCheckResult.getRootAsWordCheckResult(new ByteBuffer(buf)); + return { word: s(r.word()), legal: r.legal() }; +} + +export function decodeHistory(buf: Uint8Array): History { + const h = fb.History.getRootAsHistory(new ByteBuffer(buf)); + const moves: MoveRecord[] = []; + for (let i = 0; i < h.movesLength(); i++) { + const m = h.moves(i); + if (m) moves.push(decodeMove(m)); + } + return { gameId: s(h.gameId()), moves }; +} + +export function decodeGameList(buf: Uint8Array): GameList { + const gl = fb.GameList.getRootAsGameList(new ByteBuffer(buf)); + const games: GameView[] = []; + for (let i = 0; i < gl.gamesLength(); i++) { + const g = gl.games(i); + if (g) games.push(decodeGameView(g)); + } + return { games }; +} + +export function decodeMatchResult(buf: Uint8Array): MatchResult { + const m = fb.MatchResult.getRootAsMatchResult(new ByteBuffer(buf)); + const g = m.game(); + return { matched: m.matched(), game: m.matched() && g ? decodeGameView(g) : undefined }; +} + +export function decodeChatMessage(buf: Uint8Array): ChatMessage { + return decodeChatMsg(fb.ChatMessage.getRootAsChatMessage(new ByteBuffer(buf))); +} + +export function decodeChatList(buf: Uint8Array): ChatMessage[] { + const cl = fb.ChatList.getRootAsChatList(new ByteBuffer(buf)); + const out: ChatMessage[] = []; + for (let i = 0; i < cl.messagesLength(); i++) { + const m = cl.messages(i); + if (m) out.push(decodeChatMsg(m)); + } + return out; +} + +export function decodeEvent(kind: string, payload: Uint8Array): PushEvent | null { + const bb = new ByteBuffer(payload); + switch (kind) { + case 'your_turn': { + const e = fb.YourTurnEvent.getRootAsYourTurnEvent(bb); + return { kind: 'your_turn', gameId: s(e.gameId()), deadlineUnix: Number(e.deadlineUnix()) }; + } + case 'opponent_moved': { + const e = fb.OpponentMovedEvent.getRootAsOpponentMovedEvent(bb); + return { kind: 'opponent_moved', gameId: s(e.gameId()), seat: e.seat(), action: s(e.action()), score: e.score(), total: e.total() }; + } + case 'chat_message': + return { kind: 'chat_message', message: decodeChatMsg(fb.ChatMessage.getRootAsChatMessage(bb)) }; + case 'nudge': { + const e = fb.NudgeEvent.getRootAsNudgeEvent(bb); + return { kind: 'nudge', gameId: s(e.gameId()), fromUserId: s(e.fromUserId()) }; + } + case 'match_found': { + const e = fb.MatchFoundEvent.getRootAsMatchFoundEvent(bb); + return { kind: 'match_found', gameId: s(e.gameId()) }; + } + case 'heartbeat': + return { kind: 'heartbeat' }; + default: + return null; + } +} + +function emptyGame(): GameView { + return { + id: '', + variant: 'english', + dictVersion: '', + status: '', + players: 0, + toMove: 0, + turnTimeoutSecs: 0, + moveCount: 0, + endReason: '', + seats: [], + }; +} + +function emptyMove(): MoveRecord { + return { player: 0, action: '', dir: '', mainRow: 0, mainCol: 0, tiles: [], words: [], count: 0, score: 0, total: 0 }; +} diff --git a/ui/src/lib/transport.ts b/ui/src/lib/transport.ts index fdd9a78..1d3bc5c 100644 --- a/ui/src/lib/transport.ts +++ b/ui/src/lib/transport.ts @@ -1,36 +1,137 @@ -// Placeholder for the real Connect-web + FlatBuffers transport, wired in the edge -// codegen task. Until then, selecting a non-mock mode surfaces a clear error instead -// of failing silently. The mock (lib/mock) backs `pnpm start`. +// The real Connect-RPC + FlatBuffers transport. Every unary op rides the single +// Execute envelope (message_type + FlatBuffers payload); the live stream is +// Subscribe. The session token rides in the Authorization header; domain outcomes +// come back in result_code, edge failures as Connect error codes — both normalised to +// a thrown GatewayError. In dev the Vite proxy forwards the RPC path to the h2c +// gateway; in a packaged app VITE_GATEWAY_URL points at the real origin. -import type { GatewayClient } from './client'; -import { GatewayError } from './client'; +import { Code, ConnectError, createClient } from '@connectrpc/connect'; +import { createConnectTransport } from '@connectrpc/connect-web'; +import { Gateway } from '../gen/edge/v1/edge_pb'; +import { GatewayError, type GatewayClient } from './client'; +import * as codec from './codec'; + +function toGatewayError(e: unknown): GatewayError { + if (e instanceof ConnectError) { + switch (e.code) { + case Code.Unauthenticated: + return new GatewayError('session_invalid', e.message); + case Code.ResourceExhausted: + return new GatewayError('rate_limited', e.message); + case Code.Unavailable: + return new GatewayError('unavailable', e.message); + case Code.NotFound: + return new GatewayError('not_found', e.message); + default: + return new GatewayError('internal', e.message); + } + } + return new GatewayError('unavailable', String(e)); +} + +export function createTransport(baseUrl: string): GatewayClient { + const origin = baseUrl || (typeof location !== 'undefined' ? location.origin : ''); + const transport = createConnectTransport({ baseUrl: origin, useBinaryFormat: true }); + const client = createClient(Gateway, transport); + let token: string | null = null; + + const headers = (): Record | undefined => + token ? { authorization: `Bearer ${token}` } : undefined; + + async function exec(messageType: string, payload: Uint8Array): Promise { + let res; + try { + res = await client.execute({ messageType, payload, requestId: '' }, { headers: headers() }); + } catch (e) { + throw toGatewayError(e); + } + if (res.resultCode && res.resultCode !== 'ok') throw new GatewayError(res.resultCode); + return res.payload; + } -export function createTransport(_baseUrl: string): GatewayClient { - const ni = (): never => { - throw new GatewayError('unavailable', 'real transport not wired yet'); - }; return { - setToken: () => {}, - authGuest: ni, - authEmailRequest: ni, - authEmailLogin: ni, - profileGet: ni, - gamesList: ni, - lobbyEnqueue: ni, - lobbyPoll: ni, - gameState: ni, - gameHistory: ni, - submitPlay: ni, - pass: ni, - exchange: ni, - resign: ni, - hint: ni, - evaluate: ni, - checkWord: ni, - complaint: ni, - chatPost: ni, - chatList: ni, - nudge: ni, - subscribe: ni, + setToken(t) { + token = t; + }, + + async authGuest(locale) { + return codec.decodeSession(await exec('auth.guest', codec.encodeGuestLogin(locale ?? ''))); + }, + async authEmailRequest(email) { + await exec('auth.email.request', codec.encodeEmailRequest(email)); + }, + async authEmailLogin(email, code) { + return codec.decodeSession(await exec('auth.email.login', codec.encodeEmailLogin(email, code))); + }, + + async profileGet() { + return codec.decodeProfile(await exec('profile.get', codec.empty())); + }, + async gamesList() { + return codec.decodeGameList(await exec('games.list', codec.empty())); + }, + + async lobbyEnqueue(variant) { + return codec.decodeMatchResult(await exec('lobby.enqueue', codec.encodeEnqueue(variant))); + }, + async lobbyPoll() { + return codec.decodeMatchResult(await exec('lobby.poll', codec.empty())); + }, + + async gameState(id) { + return codec.decodeStateView(await exec('game.state', codec.encodeStateRequest(id))); + }, + async gameHistory(id) { + return codec.decodeHistory(await exec('game.history', codec.encodeGameAction(id))); + }, + async submitPlay(id, dir, tiles) { + return codec.decodeMoveResult(await exec('game.submit_play', codec.encodeSubmitPlay(id, dir, tiles))); + }, + async pass(id) { + return codec.decodeMoveResult(await exec('game.pass', codec.encodeGameAction(id))); + }, + async exchange(id, tiles) { + return codec.decodeMoveResult(await exec('game.exchange', codec.encodeExchange(id, tiles))); + }, + async resign(id) { + return codec.decodeMoveResult(await exec('game.resign', codec.encodeGameAction(id))); + }, + async hint(id) { + return codec.decodeHintResult(await exec('game.hint', codec.encodeGameAction(id))); + }, + async evaluate(id, dir, tiles) { + return codec.decodeEvalResult(await exec('game.evaluate', codec.encodeEval(id, dir, tiles))); + }, + async checkWord(id, word) { + return codec.decodeWordCheck(await exec('game.check_word', codec.encodeCheckWord(id, word))); + }, + async complaint(id, word, note) { + await exec('game.complaint', codec.encodeComplaint(id, word, note)); + }, + + async chatPost(id, body) { + return codec.decodeChatMessage(await exec('chat.post', codec.encodeChatPost(id, body))); + }, + async chatList(id) { + return codec.decodeChatList(await exec('chat.list', codec.encodeGameAction(id))); + }, + async nudge(id) { + return codec.decodeChatMessage(await exec('chat.nudge', codec.encodeGameAction(id))); + }, + + subscribe(onEvent, onError) { + const ctrl = new AbortController(); + void (async () => { + try { + for await (const ev of client.subscribe({}, { headers: headers(), signal: ctrl.signal })) { + const pe = codec.decodeEvent(ev.kind, ev.payload); + if (pe) onEvent(pe); + } + } catch (e) { + if (!ctrl.signal.aborted) onError?.(toGatewayError(e)); + } + })(); + return () => ctrl.abort(); + }, }; }