Both game and snake packages had identical PlayerID types and the snake package imported game.GenerateID. Now both use player.ID and player.GenerateID from the shared player package.
129 lines
3.0 KiB
Go
129 lines
3.0 KiB
Go
package game
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/ryanhamamura/c4/db/repository"
|
|
"github.com/ryanhamamura/c4/player"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
func (gi *GameInstance) save() error {
|
|
err := saveGame(gi.queries, gi.game)
|
|
if err != nil {
|
|
log.Error().Err(err).Str("game_id", gi.game.ID).Msg("failed to save game")
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (gi *GameInstance) savePlayer(player *Player, slot int) error {
|
|
err := saveGamePlayer(gi.queries, gi.game.ID, player, slot)
|
|
if err != nil {
|
|
log.Error().Err(err).Str("game_id", gi.game.ID).Int("slot", slot).Msg("failed to save game player")
|
|
}
|
|
return err
|
|
}
|
|
|
|
// saveGame persists the game state via upsert.
|
|
func saveGame(queries *repository.Queries, g *Game) error {
|
|
var winnerUserID *string
|
|
if g.Winner != nil && g.Winner.UserID != nil {
|
|
winnerUserID = g.Winner.UserID
|
|
}
|
|
|
|
var winningCells *string
|
|
if wc := g.WinningCellsToJSON(); wc != "" {
|
|
winningCells = &wc
|
|
}
|
|
|
|
return queries.UpsertGame(context.Background(), repository.UpsertGameParams{
|
|
ID: g.ID,
|
|
Board: g.BoardToJSON(),
|
|
CurrentTurn: int64(g.CurrentTurn),
|
|
Status: int64(g.Status),
|
|
WinnerUserID: winnerUserID,
|
|
WinningCells: winningCells,
|
|
RematchGameID: g.RematchGameID,
|
|
})
|
|
}
|
|
|
|
func saveGamePlayer(queries *repository.Queries, gameID string, player *Player, slot int) error {
|
|
var userID, guestPlayerID *string
|
|
if player.UserID != nil {
|
|
userID = player.UserID
|
|
} else {
|
|
id := string(player.ID)
|
|
guestPlayerID = &id
|
|
}
|
|
|
|
return queries.CreateGamePlayer(context.Background(), repository.CreateGamePlayerParams{
|
|
GameID: gameID,
|
|
UserID: userID,
|
|
GuestPlayerID: guestPlayerID,
|
|
Nickname: player.Nickname,
|
|
Color: int64(player.Color),
|
|
Slot: int64(slot),
|
|
})
|
|
}
|
|
|
|
func loadGame(queries *repository.Queries, id string) (*Game, error) {
|
|
row, err := queries.GetGame(context.Background(), id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return gameFromRow(row)
|
|
}
|
|
|
|
func loadGamePlayers(queries *repository.Queries, id string) ([]*Player, error) {
|
|
rows, err := queries.GetGamePlayers(context.Background(), id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return playersFromRows(rows), nil
|
|
}
|
|
|
|
// Domain ↔ DB mapping helpers.
|
|
|
|
func gameFromRow(row *repository.Game) (*Game, error) {
|
|
g := &Game{
|
|
ID: row.ID,
|
|
CurrentTurn: int(row.CurrentTurn),
|
|
Status: GameStatus(row.Status),
|
|
}
|
|
|
|
if err := g.BoardFromJSON(row.Board); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if row.WinningCells != nil {
|
|
_ = g.WinningCellsFromJSON(*row.WinningCells)
|
|
}
|
|
|
|
if row.RematchGameID != nil {
|
|
g.RematchGameID = row.RematchGameID
|
|
}
|
|
|
|
return g, nil
|
|
}
|
|
|
|
func playersFromRows(rows []*repository.GamePlayer) []*Player {
|
|
players := make([]*Player, 0, len(rows))
|
|
for _, row := range rows {
|
|
p := &Player{
|
|
Nickname: row.Nickname,
|
|
Color: int(row.Color),
|
|
}
|
|
|
|
if row.UserID != nil {
|
|
p.UserID = row.UserID
|
|
p.ID = player.ID(*row.UserID)
|
|
} else if row.GuestPlayerID != nil {
|
|
p.ID = player.ID(*row.GuestPlayerID)
|
|
}
|
|
|
|
players = append(players, p)
|
|
}
|
|
return players
|
|
}
|