diff --git a/README.md b/README.md index 8f079ee..3cd64e8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # bgammon - Backgammon server powering [bgammon.org](https://bgammon.org) -[![GoDoc](https://code.rocket9labs.com/tslocum/godoc-static/raw/branch/master/badge.svg)](https://docs.rocket9labs.com/code.rocket9labs.com/tslocum/bgammon) +[![GoDoc](https://code.rocket9labs.com/tslocum/godoc-static/raw/branch/main/badge.svg)](https://docs.rocket9labs.com/code.rocket9labs.com/tslocum/bgammon) [![Translate](https://translate.codeberg.org/widget/bgammon/server/svg-badge.svg)](https://translate.codeberg.org/projects/bgammon/) [![Donate via LiberaPay](https://img.shields.io/liberapay/receives/rocket9labs.com.svg?logo=liberapay)](https://liberapay.com/rocket9labs.com) diff --git a/game.go b/game.go index 905616f..85e9f87 100644 --- a/game.go +++ b/game.go @@ -52,6 +52,8 @@ type Game struct { partialTime time.Time partialHandled bool + lastActive time.Time + boardStates [][]int8 // One board state for each move to allow undoing a move. enteredStates [][2]bool // Player 1 entered state and Player 2 entered state for each move. @@ -105,6 +107,8 @@ func (g *Game) Copy(shallow bool) *Game { partialTurn: g.partialTurn, partialTime: g.partialTime, partialHandled: g.partialHandled, + + lastActive: g.lastActive, } copy(newGame.Board, g.Board) copy(newGame.Moves, g.Moves) @@ -142,6 +146,14 @@ func (g *Game) SetPartialHandled(handled bool) { g.partialHandled = handled } +func (g *Game) LastActive() time.Time { + return g.lastActive +} + +func (g *Game) UpdateLastActive() { + g.lastActive = time.Now() +} + func (g *Game) NextPartialTurn(player int8) { if g.Started == 0 || g.Winner != 0 { return @@ -159,6 +171,8 @@ func (g *Game) NextPartialTurn(player int8) { g.partialTurn = player g.partialTime = time.Now() + + g.UpdateLastActive() } func (g *Game) NextTurn(reroll bool) { diff --git a/pkg/server/game.go b/pkg/server/game.go index 16dcce7..8475eb0 100644 --- a/pkg/server/game.go +++ b/pkg/server/game.go @@ -305,6 +305,8 @@ func (g *serverGame) addClient(client *serverClient) (spectator bool) { return spectator } + g.UpdateLastActive() + var playerNumber int8 defer func() { ev := &bgammon.EventJoined{ @@ -400,6 +402,8 @@ func (g *serverGame) removeClient(client *serverClient) { return } + g.UpdateLastActive() + ev := &bgammon.EventLeft{} ev.Player = string(client.name) diff --git a/pkg/server/server.go b/pkg/server/server.go index 7bbb2bb..573c9a7 100644 --- a/pkg/server/server.go +++ b/pkg/server/server.go @@ -333,14 +333,18 @@ func (s *server) handleGames() { } // Terminate completed matches after two minutes when only one client remains connected. - if !g.terminated() && g.Ended != 0 && g.Winner != 0 && ((g.client1 != nil && g.client2 == nil) || (g.client1 == nil && g.client2 != nil)) && time.Now().Unix()-g.Ended >= 120 { - var clients []*serverClient - g.eachClient(func(client *serverClient) { - clients = append(clients, client) - }) - for _, sc := range clients { - sc.sendNotice(gotext.GetD(sc.language, "Left completed match.")) - g.removeClient(sc) + if !g.terminated() && ((g.client1 != nil && g.client2 == nil) || (g.client1 == nil && g.client2 != nil)) { + matchTimeout := (g.allowed1 != nil || g.allowed2 != nil) && time.Since(g.LastActive()) >= 15*time.Minute + matchEnded := g.Ended != 0 && g.Winner != 0 && time.Now().Unix()-g.Ended >= 120 + if matchTimeout || matchEnded { + var clients []*serverClient + g.eachClient(func(client *serverClient) { + clients = append(clients, client) + }) + for _, sc := range clients { + sc.sendNotice(gotext.GetD(sc.language, "Left completed match.")) + g.removeClient(sc) + } } }