165 lines
3.6 KiB
Go
165 lines
3.6 KiB
Go
//go:build !js || !wasm
|
|
|
|
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"flag"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"os/exec"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"code.rocket9labs.com/tslocum/bgammon"
|
|
"code.rocket9labs.com/tslocum/boxcars/game"
|
|
"github.com/hajimehoshi/ebiten/v2"
|
|
"golang.org/x/text/language"
|
|
)
|
|
|
|
func fetchMatches(matches []*bgammon.GameListing) []*bgammon.GameListing {
|
|
url := "https://api.bgammon.org:1338/matches.json"
|
|
|
|
req, err := http.NewRequest(http.MethodGet, url, nil)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
req.Header.Set("User-Agent", "bgammon-tv")
|
|
|
|
client := http.Client{
|
|
Timeout: time.Second * 10,
|
|
}
|
|
res, err := client.Do(req)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer res.Body.Close()
|
|
|
|
body, err := io.ReadAll(res.Body)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
|
|
err = json.Unmarshal(body, &matches)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
return matches
|
|
}
|
|
|
|
func openBoxcars(boxcarsPath string, matchID int) {
|
|
cmd := exec.Command(boxcarsPath, "--join", strconv.Itoa(matchID), "--mute")
|
|
cmd.Stdout = os.Stdout
|
|
cmd.Stderr = os.Stderr
|
|
if err := cmd.Start(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func parseFlags() *game.Game {
|
|
var (
|
|
username string
|
|
password string
|
|
serverAddress string
|
|
mute bool
|
|
instant bool
|
|
fullscreen bool
|
|
windowed bool
|
|
locale string
|
|
join int
|
|
tv bool
|
|
debug int
|
|
)
|
|
flag.StringVar(&username, "username", "", "Username")
|
|
flag.StringVar(&password, "password", "", "Password")
|
|
flag.StringVar(&serverAddress, "address", game.DefaultServerAddress, "Server address")
|
|
flag.BoolVar(&mute, "mute", false, "Mute sound effects")
|
|
flag.BoolVar(&instant, "instant", false, "Instant checker movement")
|
|
flag.BoolVar(&fullscreen, "fullscreen", false, "Start in fullscreen mode")
|
|
flag.BoolVar(&windowed, "windowed", false, "Start in windowed mode")
|
|
flag.StringVar(&locale, "locale", "", "Use specified locale for translations")
|
|
flag.IntVar(&join, "join", 0, "Connect as guest and join specified match")
|
|
flag.BoolVar(&tv, "tv", false, "Spectate games continuously")
|
|
flag.IntVar(&debug, "debug", 0, "Debug level")
|
|
flag.Parse()
|
|
|
|
if game.DefaultFullscreen() {
|
|
fullscreen = true
|
|
}
|
|
|
|
var forceLanguage *language.Tag
|
|
if locale == "" {
|
|
var err error
|
|
locale, err = game.GetLocale()
|
|
if err != nil {
|
|
locale = ""
|
|
}
|
|
}
|
|
if locale != "" {
|
|
dotIndex := strings.IndexByte(locale, '.')
|
|
if dotIndex != -1 {
|
|
locale = locale[:dotIndex]
|
|
}
|
|
tag, err := language.Parse(locale)
|
|
if err == nil {
|
|
forceLanguage = &tag
|
|
}
|
|
}
|
|
game.LoadLocale(forceLanguage)
|
|
|
|
g := game.NewGame()
|
|
g.Username = username
|
|
g.Password = password
|
|
g.ServerAddress = serverAddress
|
|
g.Mute = mute
|
|
g.Instant = instant
|
|
g.JoinGame = join
|
|
|
|
if fullscreen && !windowed {
|
|
g.Fullscreen = true
|
|
ebiten.SetFullscreen(true)
|
|
}
|
|
|
|
if debug > 0 {
|
|
game.Debug = int8(debug)
|
|
}
|
|
|
|
if len(flag.Args()) > 0 {
|
|
replay, err := os.ReadFile(flag.Arg(0))
|
|
if err != nil {
|
|
log.Fatalf("failed to open replay file %s: %s", flag.Arg(0), err)
|
|
}
|
|
g.LoadReplay = replay
|
|
}
|
|
|
|
if tv {
|
|
log.Println("Watching bgammon.org TV...")
|
|
|
|
boxcarsPath, err := os.Executable()
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
} else if boxcarsPath == "" {
|
|
boxcarsPath = "boxcars"
|
|
}
|
|
|
|
var matches []*bgammon.GameListing
|
|
foundGames := make(map[int]bool)
|
|
t := time.NewTicker(15 * time.Second)
|
|
for {
|
|
matches = fetchMatches(matches[:0])
|
|
for _, match := range matches {
|
|
if match.Password || match.Players != 2 || foundGames[match.ID] {
|
|
continue
|
|
}
|
|
openBoxcars(boxcarsPath, match.ID)
|
|
foundGames[match.ID] = true
|
|
}
|
|
<-t.C
|
|
}
|
|
}
|
|
|
|
return g
|
|
}
|