Rename module path github.com/ryanhamamura/c4 to github.com/ryanhamamura/games across go.mod, all source files, and golangci config.
142 lines
3.4 KiB
Go
142 lines
3.4 KiB
Go
package snake
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/ryanhamamura/games/db/repository"
|
|
"github.com/ryanhamamura/games/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
|
|
}
|