a2s

package module
v1.0.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 13, 2022 License: MIT Imports: 10 Imported by: 16

README

Go A2S

Build Status Go Report Card GoDoc

An implementation of Source A2S Queries

Godoc is available here: https://godoc.org/github.com/rumblefrog/go-a2s

Note: Only supports Source engine and above, Goldsource is not supported

Guides

Installing

go get -u github.com/rumblefrog/go-a2s

Querying

package main

import (
    "github.com/rumblefrog/go-a2s"
)

func main() {
    client, err := a2s.NewClient("ServerIP:Port")

    if err != nil {
        // Handle error
    }

    defer client.Close()

    info, err := client.QueryInfo() // QueryInfo, QueryPlayer, QueryRules

    if err != nil {
        // Handle error
    }

    // ...
}

Setting client options

package main

import (
    "github.com/rumblefrog/go-a2s"
)

func main() {
    client, err := a2s.NewClient(
        "ServerIP:Port",
        a2s.SetMaxPacketSize(14000), // Some engine does not follow the protocol spec, and may require bigger packet buffer
        a2s.TimeoutOption(time.Second * 5), // Setting timeout option. Default is 3 seconds
        // ... Other options
    )

    if err != nil {
        // Handle error
    }

    defer client.Close()

    // ...
}

Credits

  • Dvander's Blaster for the packet logics
  • xPaw's PHP Source Query for query specific logics

Documentation

Index

Constants

View Source
const (
	DefaultTimeout       = time.Second * 3
	DefaultPort          = 27015
	DefaultMaxPacketSize = 1400
)
View Source
const (
	A2S_INFO_REQUEST  = 0x54
	A2S_INFO_RESPONSE = 0x49 // Source & up
)
View Source
const (
	A2S_PLAYER_REQUEST  = 0x55
	A2S_PLAYER_RESPONSE = 0x44 // Source & up
)
View Source
const (
	A2S_RULES_REQUEST  = 0x56
	A2S_RULES_RESPONSE = 0x45
)
View Source
const (
	A2S_PLAYER_CHALLENGE_REPLY_HEADER = 0x41
)
View Source
const (
	MULTI_PACKET_RESPONSE_HEADER = -2
)

Variables

View Source
var (
	ErrBadPacketHeader   = errors.New("Packet header mismatch")
	ErrUnsupportedHeader = errors.New("Unsupported protocol header")
)
View Source
var (
	ErrPacketOutOfBound    = errors.New("Packet out of bound")
	ErrDuplicatePacket     = errors.New("Received same packet of same index")
	ErrWrongBz2Size        = errors.New("Bad bz2 decompression size")
	ErrMismatchBz2Checksum = errors.New("Bz2 decompressed checksum mismatches")
)
View Source
var (
	ErrBadChallengeResponse = errors.New("Bad challenge response")
)
View Source
var (
	ErrBadPlayerReply = errors.New("Bad player reply")
)
View Source
var (
	ErrBadRulesReply = errors.New("Bad rules reply")
)
View Source
var (
	ErrNilOption = errors.New("Invalid client option")
)
View Source
var (
	ErrOutOfBounds = errors.New("Read out of bounds")
)

Functions

func PreOrangeBox

func PreOrangeBox(pre bool) func(*Client) error

func SetAppID

func SetAppID(appid int32) func(*Client) error

func SetMaxPacketSize added in v1.0.1

func SetMaxPacketSize(size uint32) func(*Client) error

SetMaxPacketSize changes the maximum buffer size of a UDP packet Note that some games such as squad may use a non-standard packet size Refer to the game documentation to see if this needs to be changed

func TimeoutOption

func TimeoutOption(timeout time.Duration) func(*Client) error

Types

type AppID

type AppID int32
const (
	App_TheShip AppID = 2400
)

type Client

type Client struct {
	// contains filtered or unexported fields
}

func NewClient

func NewClient(addr string, options ...func(*Client) error) (c *Client, err error)

func (*Client) Close

func (c *Client) Close() error

func (*Client) QueryInfo

func (c *Client) QueryInfo() (*ServerInfo, error)

func (*Client) QueryPlayer

func (c *Client) QueryPlayer() (*PlayerInfo, error)

func (*Client) QueryRules

func (c *Client) QueryRules() (*RulesInfo, error)

type ExtendedServerInfo

type ExtendedServerInfo struct {
	// The server's game port number.
	Port uint16 `json:"Port"`

	// Server's SteamID.
	SteamID uint64 `json:"SteamID"`

	// Tags that describe the game according to the server (for future use.)
	Keywords string `json:"Keywords"`

	// The server's 64-bit GameID. If this is present, a more accurate AppID is present in the low 24 bits. The earlier AppID could have been truncated as it was forced into 16-bit storage.
	GameID uint64 `json:"GameID"`
}

type MultiPacketHeader

type MultiPacketHeader struct {
	// Size of the packet header
	Size int

	// Same as the Goldsource server meaning.
	// However, if the most significant bit is 1, then the response was compressed with bzip2 before being cut and sent.
	ID uint32

	// The total number of packets in the response.
	Total uint8

	// The number of the packet. Starts at 0.
	Number uint8

	/*
		(Orange Box Engine and above only.)
		Maximum size of packet before packet switching occurs.
		The default value is 1248 bytes (0x04E0), but the server administrator can decrease this.
		For older engine versions: the maximum and minimum size of the packet was unchangeable.
		AppIDs which are known not to contain this field: 215, 17550, 17700, and 240 when protocol = 7.
	*/
	SplitSize uint16

	// Indicates if payload is compressed w/bzip2
	Compressed bool

	// Payload
	Payload []byte
}

type PacketBuilder

type PacketBuilder struct {
	bytes.Buffer
}

func (*PacketBuilder) WriteBytes

func (b *PacketBuilder) WriteBytes(bytes []byte)

func (*PacketBuilder) WriteCString

func (b *PacketBuilder) WriteCString(s string)

type PacketReader

type PacketReader struct {
	// contains filtered or unexported fields
}

func NewPacketReader

func NewPacketReader(b []byte) *PacketReader

func (*PacketReader) CanRead

func (r *PacketReader) CanRead(size int) error

func (*PacketReader) More

func (r *PacketReader) More() bool

func (*PacketReader) Pos

func (r *PacketReader) Pos() int

func (*PacketReader) ReadFloat32

func (r *PacketReader) ReadFloat32() float32

func (*PacketReader) ReadIPv4

func (r *PacketReader) ReadIPv4() (net.IP, error)

func (*PacketReader) ReadInt32

func (r *PacketReader) ReadInt32() int32

func (*PacketReader) ReadPort

func (r *PacketReader) ReadPort() (uint16, error)

func (*PacketReader) ReadString

func (r *PacketReader) ReadString() string

func (*PacketReader) ReadUint16

func (r *PacketReader) ReadUint16() uint16

func (*PacketReader) ReadUint32

func (r *PacketReader) ReadUint32() uint32

func (*PacketReader) ReadUint64

func (r *PacketReader) ReadUint64() uint64

func (*PacketReader) ReadUint8

func (r *PacketReader) ReadUint8() uint8

func (*PacketReader) TryReadFloat32 added in v1.0.2

func (r *PacketReader) TryReadFloat32() (float32, bool)

func (*PacketReader) TryReadInt32 added in v1.0.2

func (r *PacketReader) TryReadInt32() (int32, bool)

func (*PacketReader) TryReadString

func (r *PacketReader) TryReadString() (string, bool)

func (*PacketReader) TryReadUint32 added in v1.0.2

func (r *PacketReader) TryReadUint32() (uint32, bool)

func (*PacketReader) TryReadUint8 added in v1.0.2

func (r *PacketReader) TryReadUint8() (uint8, bool)

type Player

type Player struct {
	/*
		Index of player chunk starting from 0.
		This seems to be always 0?
	*/
	Index uint8 `json:"Index"`

	// Name of the player.
	Name string `json:"Name"`

	// Player's score (usually "frags" or "kills".)
	Score uint32 `json:"Score"`

	// Time (in seconds) player has been connected to the server.
	Duration float32 `json:"Duration"`

	// The Ship additional player info
	TheShip *TheShipPlayer `json:"TheShip,omitempty"`
}

type PlayerInfo

type PlayerInfo struct {
	// Number of players whose information was gathered.
	Count uint8 `json:"Count"`

	// Slice of pointers to each Player
	Players []*Player `json:"Players"`
}

type Rule

type Rule struct {
	Name  string `json:"Name"`
	Value string `json:"Value"`
}

type RulesInfo

type RulesInfo struct {
	// Number of rules in the response.
	Count uint16 `json:"Count"`

	// KV map of rules name to value
	Rules map[string]string `json:"Rules"`
}

type ServerInfo

type ServerInfo struct {
	// Protocol version used by the server.
	Protocol uint8 `json:"Protocol"`

	// Name of the server.
	Name string `json:"Name"`

	// Map the server has currently loaded.
	Map string `json:"Map"`

	// Name of the folder containing the game files.
	Folder string `json:"Folder"`

	// Full name of the game.
	Game string `json:"Game"`

	// Steam Application ID of game.
	ID uint16 `json:"AppID"`

	// Number of players on the server.
	Players uint8 `json:"Players"`

	// Maximum number of players the server reports it can hold.
	MaxPlayers uint8 `json:"MaxPlayers"`

	// Number of bots on the server.
	Bots uint8 `json:"Bots"`

	// Indicates the type of server
	// Rag Doll Kung Fu servers always return 0 for "Server type."
	ServerType ServerType `json:"ServerType"`

	// Indicates the operating system of the server
	ServerOS ServerOS `json:"ServerOS"`

	// Indicates whether the server requires a password
	Visibility bool `json:"Visibility"`

	// Specifies whether the server uses VAC
	VAC bool `json:"VAC"`

	// These fields only exist in a response if the server is running The Ship
	TheShip *TheShipInfo `json:"TheShip,omitempty"`

	// Version of the game installed on the server.
	Version string `json:"Version"`

	// If present, this specifies which additional data fields will be included.
	EDF uint8 `json:"EDF,omitempty"`

	ExtendedServerInfo *ExtendedServerInfo `json:"ExtendedServerInfo,omitempty"`

	SourceTV *SourceTVInfo `json:"SourceTV,omitempty"`
}

type ServerOS

type ServerOS int
const (
	ServerOS_Unknown ServerOS = iota
	ServerOS_Linux
	ServerOS_Windows
	ServerOS_Mac
)

func ParseServerOS

func ParseServerOS(env uint8) ServerOS

func (ServerOS) String

func (os ServerOS) String() string

type ServerType

type ServerType int
const (
	ServerType_Unknown ServerType = iota
	ServerType_Dedicated
	ServerType_NonDedicated
	ServerType_SourceTV
)

func ParseServerType

func ParseServerType(servertype uint8) ServerType

func (ServerType) String

func (t ServerType) String() string

type SourceTVInfo

type SourceTVInfo struct {
	// Spectator port number for SourceTV.
	Port uint16 `json:"Port"`

	// Name of the spectator server for SourceTV.
	Name string `json:"Name"`
}

type TheShipInfo

type TheShipInfo struct {
	Mode      TheShipMode `json:"Mode"`
	Witnesses uint8       `json:"Witnesses"`
	Duration  uint8       `json:"Duration"`
}

type TheShipMode

type TheShipMode int
const (
	TheShipMode_Unknown TheShipMode = iota
	TheShipMode_Hunt
	TheShipMode_Elimination
	TheShipMode_Duel
	TheShipMode_Deathmatch
	TheShipMode_VIP_Team
	TheShipMode_Team_Elimination
)

func ParseTheShipMode

func ParseTheShipMode(m uint8) TheShipMode

func (TheShipMode) String

func (m TheShipMode) String() string

type TheShipPlayer

type TheShipPlayer struct {
	// Player's deaths
	Deaths uint32 `json:"Deaths"`

	// Player's money
	Money uint32 `json:"Money"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL