little-a2s documentation

Contents

little-a2s documentation#

pypi readthedocs publish pytest pyright-lint ruff-check ruff-format

A synchronous and sans-I/O library implementing the A2S Valve Source Query protocol.

from little_a2s import A2S

with A2S.from_addr("example.com", 27015, timeout=1) as a2s:
    print(a2s.info())
    print(a2s.players())
    print(a2s.rules())

Installation#

This project requires Python 3.11 or newer. Install it from PyPI by using pip:

$ python3 -m venv
$ .venv/bin/activate
(.venv) $ pip install little-a2s

Synchronous Clients#

class little_a2s.A2S(sock, *, challenge=-1)#

Bases: object

A synchronous client for A2S queries.

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.settimeout(1)
sock.connect(("127.0.0.1", 27015))
with A2S(sock) as a2s:
    print(a2s.info())
    print(a2s.players())
    print(a2s.rules())

This follows the Source format. For the Goldsource equivalent, see A2SGoldsource.

This class supports the context manager protocol which automatically closes the socket upon exit.

Parameters:
  • sock (socket) – The UDP socket to send and receive queries from. The socket must be connected to a remote address beforehand with connect(). You may also want to set a timeout with settimeout(). Alternatively, use from_addr() to construct the socket for you.

  • challenge (int) – The initial challenge sequence to use for requests. This is optional if you close the socket and want to resume sending queries shortly afterwards without an extra challenge response. However, the server may still challenge you regardless.

classmethod from_addr(host, port, timeout=3.0, *, prefer_ipv4=True)#

Resolve the given host and create an A2S query.

Parameters:
  • host (str) – The IPv4 address, IPv6 address, or domain name to query.

  • port (int) – The port to query.

  • timeout (float | None) – The timeout to set on the socket.

  • prefer_ipv4 (bool) – If True, prefer to resolve hostnames to IPv4 addresses. This may still connect the socket to an IPv6 address so if you need more control, consider using socket.getaddrinfo() to manually create a socket and pass it to the constructor.

Raises:

OSError – The address could not be resolved.

Return type:

Self

events_received()#

Purge all outstanding events not returned by other methods.

Return type:

list[ClientEvent]

info()#

Send an A2S_INFO request and wait for a response.

Raises:
Return type:

ClientEventInfo

players()#

Send an A2S_PLAYER request and wait for a response.

Raises:
Return type:

ClientEventPlayers

rules()#

Send an A2S_RULES request and wait for a response.

Raises:
Return type:

ClientEventRules

class little_a2s.A2SGoldsource(sock, *, challenge=-1)#

Bases: A2S

A synchronous client for A2S Goldsource queries.

classmethod from_addr(host, port, timeout=3.0, *, prefer_ipv4=True)#

Resolve the given host and create an A2S query.

Parameters:
  • host (str) – The IPv4 address, IPv6 address, or domain name to query.

  • port (int) – The port to query.

  • timeout (float | None) – The timeout to set on the socket.

  • prefer_ipv4 (bool) – If True, prefer to resolve hostnames to IPv4 addresses. This may still connect the socket to an IPv6 address so if you need more control, consider using socket.getaddrinfo() to manually create a socket and pass it to the constructor.

Raises:

OSError – The address could not be resolved.

Return type:

Self

events_received()#

Purge all outstanding events not returned by other methods.

Return type:

list[ClientEvent]

info()#

Send an A2S_INFO request and wait for a response.

Raises:
Return type:

ClientEventGoldsourceInfo

players()#

Send an A2S_PLAYER request and wait for a response.

Raises:
Return type:

ClientEventPlayers

rules()#

Send an A2S_RULES request and wait for a response.

Raises:
Return type:

ClientEventRules

Protocols#

class little_a2s.A2SClientProtocol(*, challenge=-1)#

Bases: object

Implements the client-side protocol for A2S.

This follows the Source format. For the Goldsource equivalent, see A2SGoldsourceClientProtocol.

Parameters:

challenge (int) – The challenge sequence to use for requests. This can change dynamically when receiving S2C_CHALLENGE responses.

events_received()#

Return a list of events received since this last call.

Return type:

list[ClientEvent]

info()#

Create an A2S_INFO packet to send to the server.

Return type:

ClientPacketInfo

invalidate_response(id)#

Invalidate an incomplete multi-part response with the given ID.

This should be invoked after some sort of timeout.

Return type:

MultiPartResponse | None

packets_to_send()#

Return a list of packets to send since this last call.

Return type:

list[ClientPacket]

players()#

Create an A2S_PLAYER packet to send to the server.

Return type:

ClientPacketPlayers

receive_datagram(data)#

Process a packet from the server.

Raises:

ValueError – The data is malformed.

Return type:

None

rules()#

Create an A2S_RULES packet to send to the server.

Return type:

ClientPacketRules

class little_a2s.A2SGoldsourceClientProtocol(*, challenge=-1)#

Bases: A2SClientProtocol

The Goldsource variant of the A2S client protocol used by older games.

events_received()#

Return a list of events received since this last call.

Return type:

list[ClientEvent]

info()#

Create an A2S_INFO packet to send to the server.

Return type:

ClientPacketInfo

invalidate_response(id)#

Invalidate an incomplete multi-part response with the given ID.

This should be invoked after some sort of timeout.

Return type:

MultiPartResponse | None

packets_to_send()#

Return a list of packets to send since this last call.

Return type:

list[ClientPacket]

players()#

Create an A2S_PLAYER packet to send to the server.

Return type:

ClientPacketPlayers

receive_datagram(data)#

Process a packet from the server.

Raises:

ValueError – The data is malformed.

Return type:

None

rules()#

Create an A2S_RULES packet to send to the server.

Return type:

ClientPacketRules

Events#

class little_a2s.Event#

Bases: object

The base class for all A2S protocol events.

class little_a2s.ClientEvent#

Bases: Event

An A2S client protocol event.

class little_a2s.ClientEventChallenge(*, challenge)#

Bases: ClientEvent

An S2C_CHALLENGE client protocol event.

classmethod from_reader(reader)#

Parse this class from a reader.

Return type:

Self

challenge: int#

The challenge number to append to subsequent requests.

class little_a2s.ClientEventGoldsourceInfo(*, address, name, map, folder, game, players, max_players, protocol, type, environment, visibility, mod, vac, bots)#

Bases: ClientEvent

An A2S_INFO Goldsource client protocol event.

classmethod from_reader(reader)#

Parse this class from a reader.

Return type:

Self

address: str#

IP address and port of the server.

bots: int#

Number of bots on the server.

environment: Environment#

Indicates the operating system of the server.

folder: str#

Name of the folder containing the game files.

game: str#

Full name of the game.

map: str#

Map the server has currently loaded.

max_players: int#

Maximum number of players the server reports it can hold.

mod: GoldsourceMod | None#

Information about the Goldsource mod, if the game is a mod.

name: str#

Name of the server.

players: int#

Number of players on the server.

protocol: int#

Protocol version used by the server.

type: ServerType#

Indicates the type of server.

vac: VAC#

Specifies whether the server uses Valve Anti Cheat.

visibility: Visibility#

Indicates whether the server requires a password.

class little_a2s.ClientEventInfo(*, protocol, name, map, folder, game, id, players, max_players, bots, type, environment, visibility, vac, version, extra)#

Bases: ClientEvent

An A2S_INFO client protocol event.

This follows the Source format. For the Goldsource equivalent, see ClientEventGoldsourceInfo.

classmethod from_reader(reader)#

Parse this class from a reader.

Return type:

Self

bots: int#

Number of bots on the server.

environment: Environment#

Indicates the operating system of the server.

extra: ExtraInfo | None#

Extra data included with the response.

folder: str#

Name of the folder containing the game files.

game: str#

Full name of the game.

id: int#

Steam Application ID of game.

map: str#

Map the server has currently loaded.

max_players: int#

Maximum number of players the server reports it can hold.

name: str#

Name of the server.

players: int#

Number of players on the server.

protocol: int#

Protocol version used by the server.

type: ServerType#

Indicates the type of server.

vac: VAC#

Specifies whether the server uses Valve Anti Cheat.

version: str#

Version of the game installed on the server.

visibility: Visibility#

Indicates whether the server requires a password.

class little_a2s.ClientEventPlayers(*, players)#

Bases: ClientEvent

An A2S_PLAYER client protocol event.

classmethod from_reader(reader)#

Parse this class from a reader.

Return type:

Self

players: list[Player]#

List of players whose information was gathered.

class little_a2s.ClientEventRules(*, rules)#

Bases: ClientEvent

An A2S_RULES client protocol event.

classmethod from_reader(reader)#

Parse this class from a reader.

Return type:

Self

decode()#

Return all rules decoded with UTF-8.

Return type:

dict[str, str]

rules: dict[bytes, bytes]#

The server rules or configuration variables.

While the protocol states these should be UTF-8 strings, some games might provide binary data in rules which may not decode correctly as UTF-8. If you know the game doesn’t do this, you can use the decode() method for convenience.

class little_a2s.Environment(*values)#

Bases: _EnumReprMixin, IntEnum

Indicates the operating system of the server.

class little_a2s.ExtraInfo(*, port=None, steam_id=None, spectator_port=None, spectator_name=None, keywords=None, game_id=None)#

Bases: object

Extra data included with an A2S_INFO response.

classmethod from_reader(reader, flag)#

Parse this class from a reader.

Parameters:
  • reader (Reader) – The reader to consume.

  • flag (int) – The Extra Data Flag (EDF) indicating which fields are included.

Return type:

Self

game_id: int | None = None#

The server’s game ID.

keywords: str | None = None#

Tags that describe the game according to the server.

port: int | None = None#

The server’s game port number.

spectator_name: str | None = None#

The name of the spectator server for SourceTV.

spectator_port: int | None = None#

The spectator port number for SourceTV.

steam_id: int | None = None#

The server’s steam ID.

class little_a2s.GoldsourceMod(*, link, download_link, version, size, type, dll)#

Bases: object

Information about the Goldsource mod, if the game is a mod.

classmethod from_reader(reader)#

Parse this class from a reader.

Return type:

Self

dll: GoldsourceModDLL#

Indicates whether the mod uses its own DLL.

URL to download the mod. May be empty.

URL to mod website. May be empty.

size: int#

Space (in bytes) the mod takes up.

type: GoldsourceModType#

Indicates the type of mod.

version: int#

Version of mod installed on server.

class little_a2s.GoldsourceModDLL(*values)#

Bases: _EnumReprMixin, IntEnum

Indicates whether a GoldsourceMod uses its own DLL.

EXTENSION = 1#

This mod provides its own DLL.

NATIVE = 0#

This mod uses the Half-Life DLL.

class little_a2s.GoldsourceModType(*values)#

Bases: _EnumReprMixin, IntEnum

Indicates the type of mod for GoldsourceMod.

class little_a2s.Player(*, index, name, score, duration)#

Bases: object

A player returned in the A2S_PLAYER response.

duration: float#

Time (in seconds) player has been connected to the server.

index: int#

Index of player.

name: str#

Name of the player.

score: int#

Player’s score, such as kills.

class little_a2s.ServerType(*values)#

Bases: _EnumReprMixin, IntEnum

Indicates the type of server.

class little_a2s.VAC(*values)#

Bases: _EnumReprMixin, IntEnum

Specifies whether the server uses Valve Anti Cheat.

class little_a2s.Visibility(*values)#

Bases: _EnumReprMixin, IntEnum

Indicates whether the server requires a password.

Headers#

class little_a2s.Header#

Bases: object

An A2S response header.

class little_a2s.HeaderType(*values)#

Bases: _EnumReprMixin, IntEnum

MULTI = -2#

Means the response is split.

SIMPLE = -1#

Means the response isn’t split.

class little_a2s.SimpleHeader#

Bases: Header

An single-packet A2S response header.

class little_a2s.MultiHeader(*, id, current, total, size, compressed)#

Bases: Header

A multi-packet A2S response header for Source games.

compressed: Compression | None#

An optional compression header. Mostly present in ~2006-era engines.

current: int#

The number of the packet.

id: int#

Unique number assigned by server per answer.

size: int#

The maximum size of packet before packet switching occurs, usually 1248 bytes.

total: int#

The total number of packets in the response.

class little_a2s.Compression(*, size, checksum)#

Bases: object

The compression header for Source games. Mostly present in ~2006-era engines.

checksum: int#

CRC32 checksum of uncompressed response.

size: int#

Size of the whole response once it is decompressed.

class little_a2s.MultiGoldsourceHeader(*, id, current, total)#

Bases: Header

A multi-packet A2S response header for Goldsource games.

current: int#

The number of the packet.

id: int#

Unique number assigned by server per answer.

total: int#

The total number of packets in the response.

Packets#

class little_a2s.Packet#

Bases: object

The base class of all A2S packets.

class little_a2s.ClientPacket(*, header, payload, challenge)#

Bases: Packet

An A2S packet sent by the client.

This class and its subclasses can be coerced into byte streams by passing to bytes(), for example bytes(packet).

challenge: int#

The challenge number last given by the server.

header: bytes#

The header of the request.

payload: bytes#

The payload of the request.

class little_a2s.ClientPacketInfo(*, challenge=-1)#

Bases: ClientPacket

An A2S_INFO packet sent by the client.

challenge: int = -1#

The challenge number last given by the server.

header: bytes = b'\xff\xff\xff\xffT'#

The header of the request.

payload: bytes = b'Source Engine Query\x00'#

The payload of the request.

class little_a2s.ClientPacketPlayers(*, challenge=-1)#

Bases: ClientPacket

An A2S_PLAYER packet sent by the client.

challenge: int = -1#

The challenge number last given by the server.

header: bytes = b'\xff\xff\xff\xffU'#

The header of the request.

payload: bytes = b''#

The payload of the request.

class little_a2s.ClientPacketRules(*, challenge=-1)#

Bases: ClientPacket

An A2S_RULES packet sent by the client.

challenge: int = -1#

The challenge number last given by the server.

header: bytes = b'\xff\xff\xff\xffV'#

The header of the request.

payload: bytes = b''#

The payload of the request.

Utilities#

class little_a2s.MultiPartResponse(*, id, total, compressed, payloads=<factory>)#

Bases: object

A multi-part response waiting to be assembled.

add(header, payload)#

Add a payload with the given header to the response.

Return type:

None

assemble()#

Assemble the payload together if all parts have been received.

Return type:

bytes | None

compressed: Compression | None#

An optional compression header. Mostly present in ~2006-era engines.

id: int#

Unique number assigned by server per answer.

payloads: dict[int, bytes]#

A sequenced mapping of payloads to be assembled.

total: int#

The total number of packets in the response.

class little_a2s.Readable(*args, **kwargs)#

Bases: Protocol

read(n=-1, /)#

Read up to n bytes, or the entire stream if n is negative.

Return type:

bytes

class little_a2s.Reader(data)#

Bases: object

A simple reader for parsing serialized data.

read(n=-1, /)#

Read exactly n bytes, or the entire stream if n is negative.

Raises:

EOFError – Not enough bytes could be read.

Return type:

bytes

read_byte()#

Read a single unsigned byte.

Raises:

EOFError – Not enough bytes could be read.

Return type:

int

read_char()#

Read a single ASCII character.

Raises:

EOFError – Not enough bytes could be read.

Return type:

str

read_float()#

Read a 32-bit float.

Raises:

EOFError – Not enough bytes could be read.

Return type:

float

read_long()#

Read a signed 32-bit integer.

Raises:

EOFError – Not enough bytes could be read.

Return type:

int

read_null()#

Read a null byte.

Raises:
Return type:

Literal[0]

read_null_string()#

Read a null-terminated byte string.

Raises:

EOFError – Not enough bytes could be read.

Return type:

bytes

read_null_utf8()#

Read a null-terminated, UTF-8 decoded string.

Raises:
Return type:

str

read_short()#

Read a signed 16-bit integer.

Raises:

EOFError – Not enough bytes could be read.

Return type:

int

read_uint64()#

Read an unsigned 64-bit integer.

Raises:

EOFError – Not enough bytes could be read.

Return type:

int

read_ulong()#

Read an unsigned 32-bit integer.

Raises:

EOFError – Not enough bytes could be read.

Return type:

int

read_until(sep)#

Read until the sep character is found and return all bytes before sep.

Raises:

EOFError – Not enough bytes could be read.

Return type:

bytes

read_ushort()#

Read an unsigned 16-bit integer.

Raises:

EOFError – Not enough bytes could be read.

Return type:

int

read_varchar1()#

Read a byte length and then return exactly length bytes.

Raises:

EOFError – Not enough bytes could be read.

Return type:

bytes

read_varchar2()#

Read a 2-byte length and then return exactly length bytes.

Raises:

EOFError – Not enough bytes could be read.

Return type:

bytes

read_varchar4()#

Read a 4-byte length and then return exactly length bytes.

Raises:

EOFError – Not enough bytes could be read.

Return type:

bytes

read_varchar8()#

Read an 8-byte length and then return exactly length bytes.

Raises:

EOFError – Not enough bytes could be read.

Return type:

bytes

little_a2s.filter_type(t, it, /)#

Filter through an iterable for elements of the given type.

Return type:

Iterator[TypeVar(T)]

little_a2s.first(t, it, /)#

Return the first element of the given type in an iterable.

Return type:

Optional[TypeVar(T)]

little_a2s.last(t, it, /)#

Return the last element of the given type in an iterable.

Return type:

Optional[TypeVar(T)]