add ability capture frames for later serving
Some checks are pending
Test / Format (gofmt) (push) Waiting to run
Test / Lint (golangci-lint) (push) Waiting to run
Test / Test (go test) (push) Blocked by required conditions
Test / Build CLI (go install) (push) Blocked by required conditions

This commit is contained in:
Bhavnoor Singh Saroya 2025-08-15 12:18:20 -07:00
parent 13cdcc771a
commit 8d35f26ac2
4 changed files with 168 additions and 5 deletions

View file

@ -21,11 +21,22 @@ import (
"github.com/BattlesnakeOfficial/rules/client"
"github.com/BattlesnakeOfficial/rules/maps"
"github.com/google/uuid"
_ "github.com/mattn/go-sqlite3" // the SQLite driver (underscore means we only init it)
"github.com/pkg/browser"
"github.com/spf13/cobra"
log "github.com/spf13/jwalterweatherman"
)
type Frame struct {
Turn int
State string
}
type GameMetadata struct {
BoardSize int
Winner string
}
// Used to store state for each SnakeState while running a local game
type SnakeState struct {
URL string
@ -216,6 +227,20 @@ func (gameState *GameState) Run() error {
}
boardServer := board.NewBoardServer(boardGame)
if gameState.outputFile != nil {
bytes, err := json.Marshal(boardGame)
if err != nil {
log.WARN.Printf("Failed to serialize frame event for turn%v", err)
} else {
bytes = append(bytes, '\n') // write each event on its own line
if _, err := gameState.outputFile.Write(bytes); err != nil {
log.WARN.Printf("Failed to write frame event to file: %v", err)
} else {
log.INFO.Printf("Wrote initial get state to output file")
}
}
}
if gameState.ViewInBrowser {
serverURL, err := boardServer.Listen()
if err != nil {
@ -328,18 +353,45 @@ func (gameState *GameState) Run() error {
}
if gameState.ViewInBrowser {
boardServer.SendEvent(board.GameEvent{
endEvent := board.GameEvent{
EventType: board.EVENT_TYPE_GAME_END,
Data: boardGame,
})
}
// boardServer.SendEvent(board.GameEvent{
// EventType: board.EVENT_TYPE_GAME_END,
// Data: boardGame,
// })
boardServer.SendEvent(endEvent)
if gameState.outputFile != nil {
bytes, err := json.Marshal(endEvent)
if err != nil {
// log.WARN.Printf("Unable to serialize game end event: %v", err)
} else {
if _, err := gameState.outputFile.Write(bytes); err != nil {
log.WARN.Printf("Unable to write game end event to output file: %v", err)
} else {
log.INFO.Printf("Wrote game end event to output file")
}
}
// // log.INFO.Printf("wrote frame event for game end")
}
}
if exportGame {
lines, err := gameExporter.FlushToFile(gameState.outputFile)
// lines, err := gameExporter.FlushToFile(gameState.outputFile)
lines, err := gameExporter.FlushToFile(io.Discard)
if err != nil {
return fmt.Errorf("Unable to export game: %w", err)
}
log.INFO.Printf("Wrote %d lines to output file: %s", lines, gameState.OutputPath)
log.INFO.Printf("Fake Wrote %d lines to output file: %s", lines, gameState.OutputPath)
}
return nil
@ -779,10 +831,27 @@ func (gameState *GameState) buildFrameEvent(boardState *rules.BoardState) board.
Hazards: boardState.Hazards,
}
return board.GameEvent{
gameEvent := board.GameEvent{
EventType: board.EVENT_TYPE_FRAME,
Data: gameFrame,
}
// === New: Write frame event to output file if set ===
if gameState.outputFile != nil {
bytes, err := json.Marshal(gameEvent)
if err != nil {
log.WARN.Printf("Failed to serialize frame event for turn %d: %v", boardState.Turn, err)
} else {
bytes = append(bytes, '\n') // write each event on its own line
if _, err := gameState.outputFile.Write(bytes); err != nil {
log.WARN.Printf("Failed to write frame event to file: %v", err)
} else {
log.INFO.Printf("Wrote frame event for turn %d to output file", boardState.Turn)
}
}
}
return gameEvent
}
func serialiseSnakeRequest(snakeRequest client.SnakeRequest) []byte {