|
@ -4,7 +4,8 @@ from typing import List |
|
|
from a2s.exceptions import BrokenMessageError |
|
|
from a2s.exceptions import BrokenMessageError |
|
|
from a2s.defaults import DEFAULT_TIMEOUT, DEFAULT_ENCODING, \ |
|
|
from a2s.defaults import DEFAULT_TIMEOUT, DEFAULT_ENCODING, \ |
|
|
DEFAULT_RETRIES |
|
|
DEFAULT_RETRIES |
|
|
from a2s.a2sstream import request |
|
|
from a2s.a2sstream import A2SStream |
|
|
|
|
|
from a2s.a2sasync import A2SStreamAsync |
|
|
from a2s.byteio import ByteReader |
|
|
from a2s.byteio import ByteReader |
|
|
from a2s.datacls import DataclsMeta |
|
|
from a2s.datacls import DataclsMeta |
|
|
|
|
|
|
|
@ -26,13 +27,28 @@ class Player(metaclass=DataclsMeta): |
|
|
"""Time the player has been connected to the server""" |
|
|
"""Time the player has been connected to the server""" |
|
|
duration: float |
|
|
duration: float |
|
|
|
|
|
|
|
|
def players(address, timeout=DEFAULT_TIMEOUT, |
|
|
def players_response(reader): |
|
|
encoding=DEFAULT_ENCODING): |
|
|
player_count = reader.read_uint8() |
|
|
return players_impl(address, timeout, encoding) |
|
|
resp = [ |
|
|
|
|
|
Player( |
|
|
|
|
|
index=reader.read_uint8(), |
|
|
|
|
|
name=reader.read_cstring(), |
|
|
|
|
|
score=reader.read_int32(), |
|
|
|
|
|
duration=reader.read_float() |
|
|
|
|
|
) |
|
|
|
|
|
for player_num in range(player_count) |
|
|
|
|
|
] |
|
|
|
|
|
|
|
|
def players_impl(address, timeout, encoding, challenge=0, retries=0): |
|
|
return resp |
|
|
resp_data = request( |
|
|
|
|
|
address, b"\x55" + challenge.to_bytes(4, "little"), timeout) |
|
|
def players(address, timeout=DEFAULT_TIMEOUT, encoding=DEFAULT_ENCODING): |
|
|
|
|
|
conn = A2SStream(address, timeout) |
|
|
|
|
|
reader = players_request(conn, encoding) |
|
|
|
|
|
conn.close() |
|
|
|
|
|
return players_response(reader) |
|
|
|
|
|
|
|
|
|
|
|
def players_request(conn, encoding, challenge=0, retries=0): |
|
|
|
|
|
resp_data = conn.request(b"\x55" + challenge.to_bytes(4, "little")) |
|
|
reader = ByteReader( |
|
|
reader = ByteReader( |
|
|
io.BytesIO(resp_data), endian="<", encoding=encoding) |
|
|
io.BytesIO(resp_data), endian="<", encoding=encoding) |
|
|
|
|
|
|
|
@ -43,21 +59,36 @@ def players_impl(address, timeout, encoding, challenge=0, retries=0): |
|
|
"Server keeps sending challenge responses") |
|
|
"Server keeps sending challenge responses") |
|
|
challenge = reader.read_uint32() |
|
|
challenge = reader.read_uint32() |
|
|
return players_impl( |
|
|
return players_impl( |
|
|
address, timeout, encoding, challenge, retries + 1) |
|
|
conn, encoding, challenge, retries + 1) |
|
|
|
|
|
|
|
|
if response_type != A2S_PLAYER_RESPONSE: |
|
|
if response_type != A2S_PLAYER_RESPONSE: |
|
|
raise BrokenMessageError( |
|
|
raise BrokenMessageError( |
|
|
"Invalid response type: " + str(response_type)) |
|
|
"Invalid response type: " + str(response_type)) |
|
|
|
|
|
|
|
|
player_count = reader.read_uint8() |
|
|
return reader |
|
|
resp = [ |
|
|
|
|
|
Player( |
|
|
|
|
|
index=reader.read_uint8(), |
|
|
|
|
|
name=reader.read_cstring(), |
|
|
|
|
|
score=reader.read_int32(), |
|
|
|
|
|
duration=reader.read_float() |
|
|
|
|
|
) |
|
|
|
|
|
for player_num in range(player_count) |
|
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
return resp |
|
|
async def players_async(address, timeout=DEFAULT_TIMEOUT, encoding=DEFAULT_ENCODING): |
|
|
|
|
|
conn = await A2SStream.create(address, timeout) |
|
|
|
|
|
reader = await players_request_async(conn, encoding) |
|
|
|
|
|
conn.close() |
|
|
|
|
|
return players_response(reader) |
|
|
|
|
|
|
|
|
|
|
|
async def players_request_async(conn, encoding, challenge=0, retries=0): |
|
|
|
|
|
resp_data = await conn.request(b"\x55" + challenge.to_bytes(4, "little")) |
|
|
|
|
|
reader = ByteReader( |
|
|
|
|
|
io.BytesIO(resp_data), endian="<", encoding=encoding) |
|
|
|
|
|
|
|
|
|
|
|
response_type = reader.read_uint8() |
|
|
|
|
|
if response_type == A2S_CHALLENGE_RESPONSE: |
|
|
|
|
|
if retries >= DEFAULT_RETRIES: |
|
|
|
|
|
raise BrokenMessageError( |
|
|
|
|
|
"Server keeps sending challenge responses") |
|
|
|
|
|
challenge = reader.read_uint32() |
|
|
|
|
|
return await players_impl( |
|
|
|
|
|
conn, encoding, challenge, retries + 1) |
|
|
|
|
|
|
|
|
|
|
|
if response_type != A2S_PLAYER_RESPONSE: |
|
|
|
|
|
raise BrokenMessageError( |
|
|
|
|
|
"Invalid response type: " + str(response_type)) |
|
|
|
|
|
|
|
|
|
|
|
return reader |
|
|