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.
142 lines
3.4 KiB
Go
142 lines
3.4 KiB
Go
package snake
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/ryanhamamura/c4/db/repository"
|
|
"github.com/ryanhamamura/c4/player"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
)
|
|
|
|
func (si *SnakeGameInstance) save() error {
|
|
err := saveSnakeGame(si.queries, si.game)
|
|
if err != nil {
|
|
log.Error().Err(err).Str("game_id", si.game.ID).Msg("failed to save snake game")
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (si *SnakeGameInstance) savePlayer(player *Player) error {
|
|
err := saveSnakePlayer(si.queries, si.game.ID, player)
|
|
if err != nil {
|
|
log.Error().Err(err).Str("game_id", si.game.ID).Msg("failed to save snake player")
|
|
}
|
|
return err
|
|
}
|
|
|
|
// saveSnakeGame persists the snake game state via upsert.
|
|
func saveSnakeGame(queries *repository.Queries, sg *SnakeGame) error {
|
|
boardJSON := "{}"
|
|
var gridWidth, gridHeight *int64
|
|
if sg.State != nil {
|
|
boardJSON = sg.State.ToJSON()
|
|
w, h := int64(sg.State.Width), int64(sg.State.Height)
|
|
gridWidth, gridHeight = &w, &h
|
|
}
|
|
|
|
var winnerUserID *string
|
|
if sg.Winner != nil && sg.Winner.UserID != nil {
|
|
winnerUserID = sg.Winner.UserID
|
|
}
|
|
|
|
return queries.UpsertSnakeGame(context.Background(), repository.UpsertSnakeGameParams{
|
|
ID: sg.ID,
|
|
Board: boardJSON,
|
|
Status: int64(sg.Status),
|
|
GridWidth: gridWidth,
|
|
GridHeight: gridHeight,
|
|
GameMode: int64(sg.Mode),
|
|
SnakeSpeed: int64(sg.Speed),
|
|
WinnerUserID: winnerUserID,
|
|
RematchGameID: sg.RematchGameID,
|
|
Score: int64(sg.Score),
|
|
})
|
|
}
|
|
|
|
func saveSnakePlayer(queries *repository.Queries, gameID string, player *Player) error {
|
|
var userID, guestPlayerID *string
|
|
if player.UserID != nil {
|
|
userID = player.UserID
|
|
} else {
|
|
id := string(player.ID)
|
|
guestPlayerID = &id
|
|
}
|
|
|
|
return queries.CreateSnakePlayer(context.Background(), repository.CreateSnakePlayerParams{
|
|
GameID: gameID,
|
|
UserID: userID,
|
|
GuestPlayerID: guestPlayerID,
|
|
Nickname: player.Nickname,
|
|
Color: int64(player.Slot + 1),
|
|
Slot: int64(player.Slot),
|
|
})
|
|
}
|
|
|
|
func loadSnakeGame(queries *repository.Queries, id string) (*SnakeGame, error) {
|
|
row, err := queries.GetSnakeGame(context.Background(), id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return snakeGameFromRow(row)
|
|
}
|
|
|
|
func loadSnakePlayers(queries *repository.Queries, id string) ([]*Player, error) {
|
|
rows, err := queries.GetSnakePlayers(context.Background(), id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return snakePlayersFromRows(rows), nil
|
|
}
|
|
|
|
// Domain ↔ DB mapping helpers.
|
|
|
|
func snakeGameFromRow(row *repository.Game) (*SnakeGame, error) {
|
|
state, err := GameStateFromJSON(row.Board)
|
|
if err != nil {
|
|
state = &GameState{}
|
|
}
|
|
if row.GridWidth != nil {
|
|
state.Width = int(*row.GridWidth)
|
|
}
|
|
if row.GridHeight != nil {
|
|
state.Height = int(*row.GridHeight)
|
|
}
|
|
|
|
sg := &SnakeGame{
|
|
ID: row.ID,
|
|
State: state,
|
|
Players: make([]*Player, 8),
|
|
Status: Status(row.Status),
|
|
Mode: GameMode(row.GameMode),
|
|
Score: int(row.Score),
|
|
Speed: int(row.SnakeSpeed),
|
|
}
|
|
|
|
if row.RematchGameID != nil {
|
|
sg.RematchGameID = row.RematchGameID
|
|
}
|
|
|
|
return sg, nil
|
|
}
|
|
|
|
func snakePlayersFromRows(rows []*repository.GamePlayer) []*Player {
|
|
players := make([]*Player, 0, len(rows))
|
|
for _, row := range rows {
|
|
p := &Player{
|
|
Nickname: row.Nickname,
|
|
Slot: int(row.Slot),
|
|
}
|
|
|
|
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
|
|
}
|