updated slapapi
This commit is contained in:
@@ -1,12 +1,16 @@
|
||||
package slapshotapi
|
||||
|
||||
// Regions
|
||||
const (
|
||||
RegionEUWest = "eu-west"
|
||||
RegionNAEast = "na-east"
|
||||
RegionNACentral = "na-central"
|
||||
RegionNAWest = "na-west"
|
||||
RegionOCEEast = "oce-east"
|
||||
)
|
||||
|
||||
// Arenas - API format (used in API responses and lobby creation)
|
||||
const (
|
||||
ArenaSlapstadium = "Slapstadium"
|
||||
ArenaSlapville = "Slapville"
|
||||
ArenaSlapstadiumMini = "Slapstadium_mini"
|
||||
@@ -18,7 +22,25 @@ const (
|
||||
ArenaIsland = "Island"
|
||||
ArenaObstacles = "Obstacles"
|
||||
ArenaObstaclesXL = "Obstacles_XL"
|
||||
ArenaCyberpuck = "Cyberpuck"
|
||||
)
|
||||
|
||||
// Arenas - Display format (used in local match logs)
|
||||
const (
|
||||
ArenaDisplaySlapStadium = "Slap Stadium"
|
||||
ArenaDisplaySlapville = "Slapville"
|
||||
ArenaDisplaySlapStadiumMini = "Slap Stadium Mini"
|
||||
ArenaDisplayTableHockey = "Table Hockey"
|
||||
ArenaDisplayColosseum = "Colosseum"
|
||||
ArenaDisplaySlapvilleJumbo = "Slapville Jumbo"
|
||||
ArenaDisplaySlapstadiumXL = "Slapstadium XL"
|
||||
ArenaDisplayIsland = "Island"
|
||||
ArenaDisplayObstaclesXL = "Obstacles XL"
|
||||
ArenaDisplayCyberpuck = "Cyberpuck"
|
||||
)
|
||||
|
||||
// End reasons
|
||||
const (
|
||||
EndReasonEndOfReg = "EndOfRegulation"
|
||||
EndReasonOvertime = "Overtime"
|
||||
EndReasonHomeTeamLeft = "HomeTeamLeft"
|
||||
@@ -28,8 +50,30 @@ const (
|
||||
EndReasonForfeit = "Forfeit"
|
||||
EndReasonCancelled = "Cancelled"
|
||||
EndReasonUnknown = "Unknown"
|
||||
)
|
||||
|
||||
// Game modes
|
||||
const (
|
||||
GameModeHockey = "hockey"
|
||||
GameModeDodgePuck = "dodgepuck"
|
||||
GameModeTag = "tag"
|
||||
)
|
||||
|
||||
// Teams
|
||||
const (
|
||||
TeamHome = "home"
|
||||
TeamAway = "away"
|
||||
)
|
||||
|
||||
// Match winners
|
||||
const (
|
||||
WinnerHome = "home"
|
||||
WinnerAway = "away"
|
||||
WinnerNone = "none"
|
||||
)
|
||||
|
||||
// Match types
|
||||
const (
|
||||
MatchTypePublic = "public"
|
||||
MatchTypePrivate = "private"
|
||||
)
|
||||
|
||||
53
pkg/slapshotapi/games.go
Normal file
53
pkg/slapshotapi/games.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package slapshotapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type endpointGame struct {
|
||||
gameID string
|
||||
}
|
||||
|
||||
func getEndpointGame(gameID string) *endpointGame {
|
||||
return &endpointGame{
|
||||
gameID: gameID,
|
||||
}
|
||||
}
|
||||
|
||||
func (ep *endpointGame) path() string {
|
||||
return fmt.Sprintf("/api/public/games/%s", ep.gameID)
|
||||
}
|
||||
|
||||
func (ep *endpointGame) method() string {
|
||||
return "GET"
|
||||
}
|
||||
|
||||
// ErrGameNotFound is returned when a game ID does not match any known game
|
||||
var ErrGameNotFound = errors.New("game not found")
|
||||
|
||||
// GetGame retrieves match details for a specific game by its ID.
|
||||
func (c *SlapAPI) GetGame(
|
||||
ctx context.Context,
|
||||
gameID string,
|
||||
) (*Game, error) {
|
||||
if gameID == "" {
|
||||
return nil, errors.New("gameID cannot be empty")
|
||||
}
|
||||
endpoint := getEndpointGame(gameID)
|
||||
data, err := c.request(ctx, endpoint)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "404") {
|
||||
return nil, ErrGameNotFound
|
||||
}
|
||||
return nil, errors.Wrap(err, "c.request")
|
||||
}
|
||||
game, err := unmarshal[Game](data)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unmarshal")
|
||||
}
|
||||
return game, nil
|
||||
}
|
||||
187
pkg/slapshotapi/lobbies.go
Normal file
187
pkg/slapshotapi/lobbies.go
Normal file
@@ -0,0 +1,187 @@
|
||||
package slapshotapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// --- Get Lobby ---
|
||||
|
||||
type endpointGetLobby struct {
|
||||
lobbyID string
|
||||
}
|
||||
|
||||
func getEndpointGetLobby(lobbyID string) *endpointGetLobby {
|
||||
return &endpointGetLobby{lobbyID: lobbyID}
|
||||
}
|
||||
|
||||
func (ep *endpointGetLobby) path() string {
|
||||
return fmt.Sprintf("/api/public/lobbies/%s", ep.lobbyID)
|
||||
}
|
||||
|
||||
func (ep *endpointGetLobby) method() string {
|
||||
return "GET"
|
||||
}
|
||||
|
||||
// ErrLobbyNotFound is returned when a lobby ID does not match any known lobby
|
||||
var ErrLobbyNotFound = errors.New("lobby not found")
|
||||
|
||||
// GetLobby retrieves details for a specific lobby by its ID.
|
||||
func (c *SlapAPI) GetLobby(
|
||||
ctx context.Context,
|
||||
lobbyID string,
|
||||
) (*Lobby, error) {
|
||||
if lobbyID == "" {
|
||||
return nil, errors.New("lobbyID cannot be empty")
|
||||
}
|
||||
endpoint := getEndpointGetLobby(lobbyID)
|
||||
data, err := c.request(ctx, endpoint)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "404") {
|
||||
return nil, ErrLobbyNotFound
|
||||
}
|
||||
return nil, errors.Wrap(err, "c.request")
|
||||
}
|
||||
lobby, err := unmarshal[Lobby](data)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unmarshal")
|
||||
}
|
||||
return lobby, nil
|
||||
}
|
||||
|
||||
// --- Get Lobby Matches ---
|
||||
|
||||
type endpointGetLobbyMatches struct {
|
||||
lobbyID string
|
||||
}
|
||||
|
||||
func getEndpointGetLobbyMatches(lobbyID string) *endpointGetLobbyMatches {
|
||||
return &endpointGetLobbyMatches{lobbyID: lobbyID}
|
||||
}
|
||||
|
||||
func (ep *endpointGetLobbyMatches) path() string {
|
||||
return fmt.Sprintf("/api/public/lobbies/%s/matches", ep.lobbyID)
|
||||
}
|
||||
|
||||
func (ep *endpointGetLobbyMatches) method() string {
|
||||
return "GET"
|
||||
}
|
||||
|
||||
// GetLobbyMatches retrieves the list of matches played in a specific lobby.
|
||||
func (c *SlapAPI) GetLobbyMatches(
|
||||
ctx context.Context,
|
||||
lobbyID string,
|
||||
) ([]Game, error) {
|
||||
if lobbyID == "" {
|
||||
return nil, errors.New("lobbyID cannot be empty")
|
||||
}
|
||||
endpoint := getEndpointGetLobbyMatches(lobbyID)
|
||||
data, err := c.request(ctx, endpoint)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "404") {
|
||||
return nil, ErrLobbyNotFound
|
||||
}
|
||||
return nil, errors.Wrap(err, "c.request")
|
||||
}
|
||||
var games []Game
|
||||
err = json.Unmarshal(data, &games)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "json.Unmarshal")
|
||||
}
|
||||
return games, nil
|
||||
}
|
||||
|
||||
// --- Create Lobby ---
|
||||
|
||||
type endpointCreateLobby struct {
|
||||
request LobbyCreationRequest
|
||||
}
|
||||
|
||||
func getEndpointCreateLobby(req LobbyCreationRequest) *endpointCreateLobby {
|
||||
return &endpointCreateLobby{request: req}
|
||||
}
|
||||
|
||||
func (ep *endpointCreateLobby) path() string {
|
||||
return "/api/public/lobbies"
|
||||
}
|
||||
|
||||
func (ep *endpointCreateLobby) method() string {
|
||||
return "POST"
|
||||
}
|
||||
|
||||
func (ep *endpointCreateLobby) body() ([]byte, error) {
|
||||
data, err := json.Marshal(ep.request)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "json.Marshal")
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// CreateLobby creates a new custom lobby with the specified settings.
|
||||
func (c *SlapAPI) CreateLobby(
|
||||
ctx context.Context,
|
||||
req LobbyCreationRequest,
|
||||
) (*LobbyCreationResponse, error) {
|
||||
if req.Region == "" {
|
||||
return nil, errors.New("region cannot be empty")
|
||||
}
|
||||
if req.Name == "" {
|
||||
return nil, errors.New("name cannot be empty")
|
||||
}
|
||||
if req.CreatorName == "" {
|
||||
return nil, errors.New("creator_name cannot be empty")
|
||||
}
|
||||
endpoint := getEndpointCreateLobby(req)
|
||||
data, err := c.request(ctx, endpoint)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "c.request")
|
||||
}
|
||||
resp, err := unmarshal[LobbyCreationResponse](data)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unmarshal")
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// --- Delete Lobby ---
|
||||
|
||||
type endpointDeleteLobby struct {
|
||||
lobbyID string
|
||||
}
|
||||
|
||||
func getEndpointDeleteLobby(lobbyID string) *endpointDeleteLobby {
|
||||
return &endpointDeleteLobby{lobbyID: lobbyID}
|
||||
}
|
||||
|
||||
func (ep *endpointDeleteLobby) path() string {
|
||||
return fmt.Sprintf("/api/public/lobbies/%s", ep.lobbyID)
|
||||
}
|
||||
|
||||
func (ep *endpointDeleteLobby) method() string {
|
||||
return "DELETE"
|
||||
}
|
||||
|
||||
// DeleteLobby deletes an existing lobby by its ID.
|
||||
// Returns true if the lobby was successfully deleted.
|
||||
func (c *SlapAPI) DeleteLobby(
|
||||
ctx context.Context,
|
||||
lobbyID string,
|
||||
) (bool, error) {
|
||||
if lobbyID == "" {
|
||||
return false, errors.New("lobbyID cannot be empty")
|
||||
}
|
||||
endpoint := getEndpointDeleteLobby(lobbyID)
|
||||
status, body, err := c.requestRaw(ctx, endpoint)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, "c.requestRaw")
|
||||
}
|
||||
if status == http.StatusNotFound {
|
||||
return false, ErrLobbyNotFound
|
||||
}
|
||||
return string(body) == "OK", nil
|
||||
}
|
||||
64
pkg/slapshotapi/matchlog.go
Normal file
64
pkg/slapshotapi/matchlog.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package slapshotapi
|
||||
|
||||
import (
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// MatchLog represents the raw JSON format of a local match log file.
|
||||
// This differs slightly from the API Game response in structure — the
|
||||
// match log is a flat object with game stats at the top level, whereas
|
||||
// the API response wraps game stats inside a nested "game_stats" field
|
||||
// alongside metadata like region, match type, and creation time.
|
||||
type MatchLog struct {
|
||||
Type string `json:"type"`
|
||||
MatchID string `json:"match_id,omitempty"`
|
||||
Winner string `json:"winner"`
|
||||
Arena string `json:"arena"`
|
||||
PeriodsEnabled string `json:"periods_enabled"`
|
||||
CurrentPeriod string `json:"current_period"`
|
||||
CustomMercyRule string `json:"custom_mercy_rule"`
|
||||
MatchLength string `json:"match_length"`
|
||||
EndReason string `json:"end_reason"`
|
||||
Score Score `json:"score"`
|
||||
Players []Player `json:"players"`
|
||||
}
|
||||
|
||||
// ParseMatchLog parses a local match log JSON file into a MatchLog struct.
|
||||
func ParseMatchLog(data []byte) (*MatchLog, error) {
|
||||
if len(data) == 0 {
|
||||
return nil, errors.New("data cannot be empty")
|
||||
}
|
||||
log, err := unmarshal[MatchLog](data)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unmarshal")
|
||||
}
|
||||
return log, nil
|
||||
}
|
||||
|
||||
// ToGameStats converts a MatchLog into a GameStats struct, normalizing the
|
||||
// local match log format into the same structure used by the API.
|
||||
func (ml *MatchLog) ToGameStats() GameStats {
|
||||
return GameStats{
|
||||
Type: ml.Type,
|
||||
Arena: ml.Arena,
|
||||
Score: ml.Score,
|
||||
Winner: ml.Winner,
|
||||
EndReason: ml.EndReason,
|
||||
MatchLength: ml.MatchLength,
|
||||
PeriodsEnabled: ml.PeriodsEnabled,
|
||||
CurrentPeriod: ml.CurrentPeriod,
|
||||
CustomMercyRule: ml.CustomMercyRule,
|
||||
Players: ml.Players,
|
||||
}
|
||||
}
|
||||
|
||||
// ToGame converts a MatchLog into a Game struct. Since match logs don't
|
||||
// contain all fields present in an API response (region, match_type,
|
||||
// gamemode, created), those fields will be empty. The match_id from the
|
||||
// log (if present) is used as the Game ID.
|
||||
func (ml *MatchLog) ToGame() Game {
|
||||
return Game{
|
||||
ID: ml.MatchID,
|
||||
GameStats: ml.ToGameStats(),
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package slapshotapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
@@ -54,9 +53,11 @@ func (c *SlapAPI) GetQueueStatus(
|
||||
endpoint := getEndpointMatchmaking(regions)
|
||||
data, err := c.request(ctx, endpoint)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "slapapiReq")
|
||||
return nil, errors.Wrap(err, "c.request")
|
||||
}
|
||||
resp, err := unmarshal[matchmakingresp](data)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unmarshal")
|
||||
}
|
||||
resp := matchmakingresp{}
|
||||
json.Unmarshal(data, &resp)
|
||||
return &resp.Playlists, nil
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package slapshotapi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@@ -14,31 +16,101 @@ type endpoint interface {
|
||||
method() string
|
||||
}
|
||||
|
||||
// bodyEndpoint is an optional interface for endpoints that send a JSON body
|
||||
type bodyEndpoint interface {
|
||||
endpoint
|
||||
body() ([]byte, error)
|
||||
}
|
||||
|
||||
func (c *SlapAPI) request(
|
||||
ctx context.Context,
|
||||
ep endpoint,
|
||||
) ([]byte, error) {
|
||||
baseurl := fmt.Sprintf("https://%s.slapshot.gg%s", c.env, ep.path())
|
||||
req, err := http.NewRequest(ep.method(), baseurl, nil)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "http.NewRequest")
|
||||
|
||||
var bodyReader io.Reader
|
||||
if bep, ok := ep.(bodyEndpoint); ok {
|
||||
data, err := bep.body()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "endpoint.body")
|
||||
}
|
||||
bodyReader = bytes.NewReader(data)
|
||||
}
|
||||
req.Header.Add("accept", "application/json")
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, ep.method(), baseurl, bodyReader)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "http.NewRequestWithContext")
|
||||
}
|
||||
req.Header.Add("Accept", "application/json")
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", c.key))
|
||||
if bodyReader != nil {
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
}
|
||||
|
||||
res, err := c.do(ctx, req)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "http.DefaultClient.Do")
|
||||
return nil, errors.Wrap(err, "c.do")
|
||||
}
|
||||
if res.StatusCode != 200 {
|
||||
return nil, errors.New(fmt.Sprintf("Error making request: %v", res.StatusCode))
|
||||
defer func() { _ = res.Body.Close() }()
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return nil, errors.New(fmt.Sprintf("API request failed with status %d", res.StatusCode))
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "io.ReadAll")
|
||||
}
|
||||
err = res.Body.Close()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "resp.Body.Close")
|
||||
}
|
||||
return body, nil
|
||||
}
|
||||
|
||||
// requestRaw performs an API request and returns the raw status code and body.
|
||||
// This is used for endpoints where non-200 status codes carry meaningful data
|
||||
// (e.g. DELETE returning a plain text response).
|
||||
func (c *SlapAPI) requestRaw(
|
||||
ctx context.Context,
|
||||
ep endpoint,
|
||||
) (int, []byte, error) {
|
||||
baseurl := fmt.Sprintf("https://%s.slapshot.gg%s", c.env, ep.path())
|
||||
|
||||
var bodyReader io.Reader
|
||||
if bep, ok := ep.(bodyEndpoint); ok {
|
||||
data, err := bep.body()
|
||||
if err != nil {
|
||||
return 0, nil, errors.Wrap(err, "endpoint.body")
|
||||
}
|
||||
bodyReader = bytes.NewReader(data)
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, ep.method(), baseurl, bodyReader)
|
||||
if err != nil {
|
||||
return 0, nil, errors.Wrap(err, "http.NewRequestWithContext")
|
||||
}
|
||||
req.Header.Add("Accept", "application/json")
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", c.key))
|
||||
if bodyReader != nil {
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
}
|
||||
|
||||
res, err := c.do(ctx, req)
|
||||
if err != nil {
|
||||
return 0, nil, errors.Wrap(err, "c.do")
|
||||
}
|
||||
defer func() { _ = res.Body.Close() }()
|
||||
|
||||
body, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return 0, nil, errors.Wrap(err, "io.ReadAll")
|
||||
}
|
||||
return res.StatusCode, body, nil
|
||||
}
|
||||
|
||||
// unmarshal is a helper that unmarshals JSON response data into a target struct
|
||||
func unmarshal[T any](data []byte) (*T, error) {
|
||||
var result T
|
||||
err := json.Unmarshal(data, &result)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "json.Unmarshal")
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package slapshotapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
@@ -46,10 +45,9 @@ func (c *SlapAPI) GetSlapID(
|
||||
}
|
||||
return 0, errors.Wrap(err, "c.request")
|
||||
}
|
||||
resp := idresp{}
|
||||
err = json.Unmarshal(data, &resp)
|
||||
resp, err := unmarshal[idresp](data)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "json.Unmarshal")
|
||||
return 0, errors.Wrap(err, "unmarshal")
|
||||
}
|
||||
return resp.ID, nil
|
||||
}
|
||||
|
||||
158
pkg/slapshotapi/types.go
Normal file
158
pkg/slapshotapi/types.go
Normal file
@@ -0,0 +1,158 @@
|
||||
package slapshotapi
|
||||
|
||||
// Score represents the score for both teams in a match
|
||||
type Score struct {
|
||||
Home int `json:"home"`
|
||||
Away int `json:"away"`
|
||||
}
|
||||
|
||||
// PlayerStats contains all possible player statistics from a match.
|
||||
// Fields use pointers because not every stat is present in every match response.
|
||||
type PlayerStats struct {
|
||||
Goals *float64 `json:"goals,omitempty"`
|
||||
Assists *float64 `json:"assists,omitempty"`
|
||||
PrimaryAssists *float64 `json:"primary_assists,omitempty"`
|
||||
SecondaryAssists *float64 `json:"secondary_assists,omitempty"`
|
||||
Saves *float64 `json:"saves,omitempty"`
|
||||
Blocks *float64 `json:"blocks,omitempty"`
|
||||
Shots *float64 `json:"shots,omitempty"`
|
||||
Turnovers *float64 `json:"turnovers,omitempty"`
|
||||
Takeaways *float64 `json:"takeaways,omitempty"`
|
||||
Passes *float64 `json:"passes,omitempty"`
|
||||
PossessionTime *float64 `json:"possession_time_sec,omitempty"`
|
||||
FaceoffsWon *float64 `json:"faceoffs_won,omitempty"`
|
||||
FaceoffsLost *float64 `json:"faceoffs_lost,omitempty"`
|
||||
PostHits *float64 `json:"post_hits,omitempty"`
|
||||
OvertimeGoals *float64 `json:"overtime_goals,omitempty"`
|
||||
GameWinningGoals *float64 `json:"game_winning_goals,omitempty"`
|
||||
Score *float64 `json:"score,omitempty"`
|
||||
ContributedGoals *float64 `json:"contributed_goals,omitempty"`
|
||||
ConcededGoals *float64 `json:"conceded_goals,omitempty"`
|
||||
GamesPlayed *float64 `json:"games_played,omitempty"`
|
||||
Wins *float64 `json:"wins,omitempty"`
|
||||
Losses *float64 `json:"losses,omitempty"`
|
||||
OvertimeWins *float64 `json:"overtime_wins,omitempty"`
|
||||
OvertimeLosses *float64 `json:"overtime_losses,omitempty"`
|
||||
Ties *float64 `json:"ties,omitempty"`
|
||||
Shutouts *float64 `json:"shutouts,omitempty"`
|
||||
ShutsAgainst *float64 `json:"shutouts_against,omitempty"`
|
||||
HasMercyRuled *float64 `json:"has_mercy_ruled,omitempty"`
|
||||
WasMercyRuled *float64 `json:"was_mercy_ruled,omitempty"`
|
||||
PeriodsPlayed *float64 `json:"periods_played,omitempty"`
|
||||
}
|
||||
|
||||
// Player represents a single player's data in a match
|
||||
type Player struct {
|
||||
GameUserID string `json:"game_user_id"`
|
||||
Team string `json:"team"`
|
||||
Username string `json:"username"`
|
||||
Stats PlayerStats `json:"stats"`
|
||||
}
|
||||
|
||||
// GameStats contains the in-game statistics and settings for a match.
|
||||
// This is the core match data returned both by the API and in local match logs.
|
||||
type GameStats struct {
|
||||
Type string `json:"type"`
|
||||
Arena string `json:"arena"`
|
||||
Score Score `json:"score"`
|
||||
Winner string `json:"winner"`
|
||||
EndReason string `json:"end_reason"`
|
||||
MatchLength string `json:"match_length"`
|
||||
PeriodsEnabled string `json:"periods_enabled"`
|
||||
CurrentPeriod string `json:"current_period"`
|
||||
CustomMercyRule string `json:"custom_mercy_rule"`
|
||||
Players []Player `json:"players"`
|
||||
}
|
||||
|
||||
// Game represents a full match as returned by the API /games/{id} endpoint
|
||||
type Game struct {
|
||||
ID string `json:"id"`
|
||||
Region string `json:"region"`
|
||||
MatchType string `json:"match_type"`
|
||||
Gamemode string `json:"gamemode"`
|
||||
Created string `json:"created"`
|
||||
GameStats GameStats `json:"game_stats"`
|
||||
}
|
||||
|
||||
// LobbyPlayer represents a player in a lobby
|
||||
type LobbyPlayer struct {
|
||||
ID int `json:"id"`
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
// LobbyTeams represents the team assignments in a lobby
|
||||
type LobbyTeams struct {
|
||||
Home []LobbyPlayer `json:"home"`
|
||||
Away []LobbyPlayer `json:"away"`
|
||||
Spectators []LobbyPlayer `json:"spectators"`
|
||||
}
|
||||
|
||||
// Lobby represents a custom lobby as returned by the API
|
||||
type Lobby struct {
|
||||
UUID string `json:"uuid"`
|
||||
Region string `json:"region"`
|
||||
Name string `json:"name"`
|
||||
HasPassword bool `json:"has_password"`
|
||||
Owner int `json:"owner"`
|
||||
OwnerName string `json:"owner_name"`
|
||||
PlayerCount int `json:"player_count"`
|
||||
MaxPlayers int `json:"max_players"`
|
||||
InGame bool `json:"in_game"`
|
||||
Players LobbyTeams `json:"players"`
|
||||
MercyRule int `json:"mercy_rule"`
|
||||
Arena string `json:"arena"`
|
||||
PeriodsEnabled bool `json:"periods_enabled"`
|
||||
CurrentPeriod int `json:"current_period"`
|
||||
Score Score `json:"score"`
|
||||
Starting bool `json:"starting"`
|
||||
CanStart bool `json:"can_start"`
|
||||
}
|
||||
|
||||
// LobbyCreationRequest contains the parameters for creating a new lobby
|
||||
type LobbyCreationRequest struct {
|
||||
Region string `json:"region"`
|
||||
Name string `json:"name"`
|
||||
Password string `json:"password"`
|
||||
CreatorName string `json:"creator_name"`
|
||||
|
||||
// Optional fields
|
||||
IsPeriods *bool `json:"is_periods,omitempty"`
|
||||
CurrentPeriod *int `json:"current_period,omitempty"`
|
||||
MatchLength *int `json:"match_length,omitempty"`
|
||||
MercyRule *int `json:"mercy_rule,omitempty"`
|
||||
Arena string `json:"arena,omitempty"`
|
||||
|
||||
InitialScore *Score `json:"initial_score,omitempty"`
|
||||
}
|
||||
|
||||
// LobbyCreationResponse is returned when a lobby is successfully created
|
||||
type LobbyCreationResponse struct {
|
||||
Success bool `json:"success"`
|
||||
LobbyID string `json:"lobby_id"`
|
||||
}
|
||||
|
||||
// MatchmakingPlayer represents a player in the matchmaking queue
|
||||
type MatchmakingPlayer struct {
|
||||
UUID int `json:"uuid"`
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
// MatchmakingRegion represents a region in a matchmaking entity
|
||||
type MatchmakingRegion struct {
|
||||
Key string `json:"key"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// MatchmakingEntity represents a group/party in the matchmaking queue
|
||||
type MatchmakingEntity struct {
|
||||
Players []MatchmakingPlayer `json:"players"`
|
||||
Regions []MatchmakingRegion `json:"regions"`
|
||||
MMR int `json:"mmr"`
|
||||
MMROffset int `json:"mmr_offset"`
|
||||
}
|
||||
|
||||
// MatchmakingResponse is the full matchmaking queue response from the API
|
||||
type MatchmakingResponse struct {
|
||||
Entities []MatchmakingEntity `json:"entities"`
|
||||
Playlists PubsQueue `json:"playlists"`
|
||||
}
|
||||
Reference in New Issue
Block a user