Record replays

This commit is contained in:
Trevor Slocum 2023-12-15 19:22:59 -08:00
parent ac522526e7
commit 5191ecb83d
5 changed files with 73 additions and 27 deletions

View file

@ -15,40 +15,37 @@ The index table consists of one or more lines in the following format:
`bgammon-replay <index>`
Games are in chronological order.
The index specifies the index of the first byte of the first line of a game.
The index is always eight digits with leading zeroes.
The index specifies the position of the first byte of the first line of a game.
The index is always eight digits in length with leading zeroes.
### Game
#### Metadata
The first line of the file specifies the metadata.
The first line of the game is the metadata.
`i <player1> <player2> <total> <score1> <score2> <winner> <points> <acey>`
#### Index table
The index table consists of one or more lines in the following format:
`g <player> <index>`
The index specifies the index of the first byte of each line corresponding to each turn in the game.
The index is always eight digits with leading zeroes.
#### Events
The remaining lines of the game are the events.
Events are in the following format:
`<player> <event>`
##### Double
Accepted:
`d 2 1`
`1 d 2 1`
Declined:
`d 2 0`
`1 d 2 0`
##### Roll and move
Moves are always specified from player 1's perspective.
`r 5-3 13/8 24/21`
`1 r 5-3 13/8 24/21`

View file

@ -48,7 +48,8 @@ CREATE TABLE game (
account2 integer NOT NULL,
points integer NOT NULL,
winner integer NOT NULL,
wintype integer NOT NULL
wintype integer NOT NULL,
replay TEXT NOT NULL DEFAULT ''
);
`
@ -387,11 +388,16 @@ func setAccountSetting(id int, name string, value int) error {
return err
}
func recordGameResult(g *bgammon.Game, winType int, account1 int, account2 int) error {
if db == nil || g.Started.IsZero() || g.Ended.IsZero() || g.Winner == 0 {
func recordGameResult(g *bgammon.Game, winType int, account1 int, account2 int, replay [][]byte) error {
if db == nil || g.Started.IsZero() || g.Winner == 0 {
return nil
}
ended := g.Ended
if ended.IsZero() {
ended = time.Now()
}
tx, err := begin()
if err != nil {
return err
@ -402,7 +408,7 @@ func recordGameResult(g *bgammon.Game, winType int, account1 int, account2 int)
if g.Acey {
acey = 1
}
_, err = tx.Exec(context.Background(), "INSERT INTO game (acey, started, ended, player1, account1, player2, account2, points, winner, wintype) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)", acey, g.Started.Unix(), g.Ended.Unix(), g.Player1.Name, account1, g.Player2.Name, account2, g.Points, g.Winner, winType)
_, err = tx.Exec(context.Background(), "INSERT INTO game (acey, started, ended, player1, account1, player2, account2, points, winner, wintype, replay) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)", acey, g.Started.Unix(), ended.Unix(), g.Player1.Name, account1, g.Player2.Name, account2, g.Points, g.Winner, winType, bytes.Join(replay, []byte("\n")))
return err
}

View file

@ -43,7 +43,7 @@ func setAccountSetting(id int, name string, value int) error {
return nil
}
func recordGameResult(g *bgammon.Game, winType int, account1 int, account2 int) error {
func recordGameResult(g *bgammon.Game, winType int, account1 int, account2 int, replay [][]byte) error {
return nil
}

View file

@ -8,6 +8,11 @@ import (
"code.rocket9labs.com/tslocum/bgammon"
)
type replayEvent struct {
Player int
Event []byte
}
type serverGame struct {
id int
created int64
@ -22,6 +27,7 @@ type serverGame struct {
rematch int
rejoin1 bool
rejoin2 bool
replay [][]byte
*bgammon.Game
}

View file

@ -992,13 +992,22 @@ COMMANDS:
cmd.client.sendNotice("Declined double offer")
clientGame.opponent(cmd.client).sendNotice(fmt.Sprintf("%s declined double offer.", cmd.client.name))
acey := 0
if clientGame.Acey {
acey = 1
}
clientGame.replay = append([][]byte{[]byte(fmt.Sprintf("i %s %s %d %d %d %d %d %d", clientGame.Player1.Name, clientGame.Player2.Name, clientGame.Points, clientGame.Player1.Points, clientGame.Player2.Points, clientGame.Winner, clientGame.DoubleValue, acey))}, clientGame.replay...)
clientGame.replay = append(clientGame.replay, []byte(fmt.Sprintf("%d d %d 0", clientGame.Turn, clientGame.DoubleValue*2)))
var reset bool
if cmd.client.playerNumber == 1 {
clientGame.Player2.Points = clientGame.Player2.Points + clientGame.DoubleValue
if clientGame.Player2.Points >= clientGame.Points {
clientGame.Winner = 2
clientGame.Ended = time.Now()
} else {
clientGame.Reset()
reset = true
}
} else {
clientGame.Player1.Points = clientGame.Player2.Points + clientGame.DoubleValue
@ -1006,7 +1015,7 @@ COMMANDS:
clientGame.Winner = 1
clientGame.Ended = time.Now()
} else {
clientGame.Reset()
reset = true
}
}
@ -1021,11 +1030,17 @@ COMMANDS:
winEvent.Player = clientGame.Player2.Name
}
err := recordGameResult(clientGame.Game, 4, clientGame.client1.account, clientGame.client2.account)
err := recordGameResult(clientGame.Game, 4, clientGame.client1.account, clientGame.client2.account, clientGame.replay)
if err != nil {
log.Fatalf("failed to record game result: %s", err)
}
}
if reset {
clientGame.Reset()
clientGame.replay = clientGame.replay[:0]
}
clientGame.eachClient(func(client *serverClient) {
clientGame.sendBoard(client)
if winEvent != nil {
@ -1273,14 +1288,23 @@ COMMANDS:
}
}
acey := 0
if clientGame.Acey {
acey = 1
}
clientGame.replay = append([][]byte{[]byte(fmt.Sprintf("i %s %s %d %d %d %d %d %d", clientGame.Player1.Name, clientGame.Player2.Name, clientGame.Points, clientGame.Player1.Points, clientGame.Player2.Points, clientGame.Winner, winPoints, acey))}, clientGame.replay...)
clientGame.replay = append(clientGame.replay, []byte(fmt.Sprintf("%d r %d-%d %s", clientGame.Turn, clientGame.Roll1, clientGame.Roll2, bgammon.FormatMoves(clientGame.Moves))))
winEvent = &bgammon.EventWin{
Points: winPoints * clientGame.DoubleValue,
}
var reset bool
if clientGame.Winner == 1 {
winEvent.Player = clientGame.Player1.Name
clientGame.Player1.Points = clientGame.Player1.Points + winPoints*clientGame.DoubleValue
if clientGame.Player1.Points < clientGame.Points {
clientGame.Reset()
reset = true
} else {
clientGame.Ended = time.Now()
}
@ -1288,7 +1312,7 @@ COMMANDS:
winEvent.Player = clientGame.Player2.Name
clientGame.Player2.Points = clientGame.Player2.Points + winPoints*clientGame.DoubleValue
if clientGame.Player2.Points < clientGame.Points {
clientGame.Reset()
reset = true
} else {
clientGame.Ended = time.Now()
}
@ -1298,10 +1322,15 @@ COMMANDS:
if clientGame.Acey {
winType = 1
}
err := recordGameResult(clientGame.Game, winType, clientGame.client1.account, clientGame.client2.account)
err := recordGameResult(clientGame.Game, winType, clientGame.client1.account, clientGame.client2.account, clientGame.replay)
if err != nil {
log.Fatalf("failed to record game result: %s", err)
}
if reset {
clientGame.Reset()
clientGame.replay = clientGame.replay[:0]
}
}
clientGame.eachClient(func(client *serverClient) {
@ -1378,6 +1407,7 @@ COMMANDS:
cmd.client.sendNotice("Accepted double.")
opponent.sendNotice(fmt.Sprintf("%s accepted double.", cmd.client.name))
clientGame.replay = append(clientGame.replay, []byte(fmt.Sprintf("%d d %d 1", clientGame.Turn, clientGame.DoubleValue)))
clientGame.eachClient(func(client *serverClient) {
clientGame.sendBoard(client)
})
@ -1405,6 +1435,10 @@ COMMANDS:
continue
}
recordEvent := func() {
clientGame.replay = append(clientGame.replay, []byte(fmt.Sprintf("%d r %d-%d %s", clientGame.Turn, clientGame.Roll1, clientGame.Roll2, bgammon.FormatMoves(clientGame.Moves))))
}
if clientGame.Acey && ((clientGame.Roll1 == 1 && clientGame.Roll2 == 2) || (clientGame.Roll1 == 2 && clientGame.Roll2 == 1)) && len(clientGame.Moves) == 2 {
var doubles int
if len(params) > 0 {
@ -1417,6 +1451,7 @@ COMMANDS:
continue
}
recordEvent()
clientGame.NextTurn(true)
clientGame.Roll1, clientGame.Roll2 = doubles, doubles
clientGame.Reroll = true
@ -1431,6 +1466,7 @@ COMMANDS:
client.sendEvent(ev)
})
} else if clientGame.Acey && clientGame.Reroll {
recordEvent()
clientGame.NextTurn(true)
clientGame.Roll1, clientGame.Roll2 = 0, 0
if !clientGame.roll(cmd.client.playerNumber) {
@ -1450,6 +1486,7 @@ COMMANDS:
clientGame.sendBoard(client)
})
} else {
recordEvent()
clientGame.NextTurn(false)
if clientGame.Winner == 0 {
gameState := &bgammon.GameState{
@ -1629,7 +1666,7 @@ COMMANDS:
clientGame.Turn = 2
clientGame.Roll1 = 4
clientGame.Roll2 = 4
clientGame.Board = []int{1, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 1, -1, 1, -1}
clientGame.Board = []int{1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -1, 0, 0}
clientGame.eachClient(func(client *serverClient) {
clientGame.sendBoard(client)