From 9ee0afdaf27e204d1c2cb82fd58eda53fb518e4c Mon Sep 17 00:00:00 2001 From: Rossen Georgiev Date: Wed, 29 Jun 2016 18:14:50 +0100 Subject: [PATCH] SC: added GameServers builtin --- docs/api/steam.client.builtins.rst | 8 ++ steam/client/builtins/__init__.py | 3 +- steam/client/builtins/gameservers.py | 159 +++++++++++++++++++++++++++ 3 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 steam/client/builtins/gameservers.py diff --git a/docs/api/steam.client.builtins.rst b/docs/api/steam.client.builtins.rst index 0aa6fe9..ce198b3 100644 --- a/docs/api/steam.client.builtins.rst +++ b/docs/api/steam.client.builtins.rst @@ -42,3 +42,11 @@ Leaderboards :members: :undoc-members: :show-inheritance: + +Game Servers +------------ + +.. automodule:: steam.client.builtins.gameservers + :members: + :undoc-members: + :show-inheritance: diff --git a/steam/client/builtins/__init__.py b/steam/client/builtins/__init__.py index f2289f3..472a394 100644 --- a/steam/client/builtins/__init__.py +++ b/steam/client/builtins/__init__.py @@ -6,8 +6,9 @@ from steam.client.builtins.user import User from steam.client.builtins.web import Web from steam.client.builtins.unified_messages import UnifiedMessages from steam.client.builtins.leaderboards import Leaderboards +from steam.client.builtins.gameservers import GameServers -class BuiltinBase(Misc, User, Web, UnifiedMessages, Leaderboards): +class BuiltinBase(Misc, User, Web, UnifiedMessages, Leaderboards, GameServers): """ This object is used as base to implement all high level functionality. The features are separated into submodules. diff --git a/steam/client/builtins/gameservers.py b/steam/client/builtins/gameservers.py new file mode 100644 index 0000000..4904882 --- /dev/null +++ b/steam/client/builtins/gameservers.py @@ -0,0 +1,159 @@ +""" +Game Servers related functionality +""" +from steam.steamid import SteamID +from steam.core.msg import MsgProto +from steam.enums.emsg import EMsg +from steam.util import ip_to_int, ip_from_int, proto_to_dict + + +class GameServers(object): + def __init__(self, *args, **kwargs): + super(GameServers, self).__init__(*args, **kwargs) + + self.gameservers = SteamGameServers(self) #: instance of :class:`SteamGameServers` + + +class SteamGameServers(object): + def __init__(self, steam): + self.steam = steam + + def query(self, filter_text, max_servers=10, **kwargs): + r""" + Query game servers + + https://developer.valvesoftware.com/wiki/Master_Server_Query_Protocol + + .. note:: + When specifying ``filter_text`` use *raw strings* otherwise python won't treat backslashes + as literal characters (e.g. ``query(r'\appid\730\white\1')``) + + :param filter_text: filter for servers + :type filter_text: str + :param max_servers: (optional) number of servers to return + :type max_servers: int + :param app_id: (optional) app id + :type app_id: int + :param geo_location_ip: (optional) ip (e.g. '1.2.3.4') + :type geo_location_ip: str + :returns: list of servers, see below. (``None`` is returned steam doesn't respond) + :rtype: :class:`list`, :class:`None` + + Sample response: + + .. code:: python + + [{'auth_players': 0, 'server_ip': '1.2.3.4', 'server_port': 27015}, + {'auth_players': 6, 'server_ip': '1.2.3.4', 'server_port': 27016}, + ... + ] + """ + if 'geo_location_ip' in kwargs: + kwargs['geo_location_ip'] = ip_to_int(kwargs['geo_location_ip']) + + kwargs['filter_text'] = filter_text + kwargs['max_servers'] = max_servers + + resp = self.steam.send_job_and_wait(MsgProto(EMsg.ClientGMSServerQuery), kwargs, timeout=30) + + if resp is None: return None + + resp = proto_to_dict(resp) + + for server in resp['servers']: + server['server_ip'] = ip_from_int(server['server_ip']) + + return resp['servers'] + + def get_server_list(self, filter_text, max_servers=10): + """ + Get list of servers. Works similiarly to :meth:`query`, but the response has more details. + + :param filter_text: filter for servers + :type filter_text: str + :param max_servers: (optional) number of servers to return + :type max_servers: int + :returns: list of servers, see below. (``None`` is returned steam doesn't respond) + :rtype: :class:`list`, :class:`None` + + + Sample response: + + .. code:: python + + [{'addr': '1.2.3.4:27067', + 'appid': 730, + 'bots': 0, + 'dedicated': True, + 'gamedir': 'csgo', + 'gameport': 27067, + 'gametype': 'valve_ds,empty,secure', + 'map': 'de_dust2', + 'max_players': 10, + 'name': 'Valve CS:GO Asia Server (srcdsXXX.XXX.XXX)', + 'os': 'l', + 'players': 0, + 'product': 'csgo', + 'region': 5, + 'secure': True, + 'steamid': SteamID(id=3279818759, type='AnonGameServer', universe='Public', instance=7011), + 'version': '1.35.4.0'} + ] + """ + resp = self.steam.unified_messages.send_and_wait("GameServers.GetServerList#1", { + "filter": filter_text, + "limit": max_servers, + }, timeout=30) + + if resp is None: return None + + resp = proto_to_dict(resp) + + for server in resp['servers']: + server['steamid'] = SteamID(server['steamid']) + + return resp['servers'] + + def get_ips_from_steamid(self, server_steam_ids): + """Resolve IPs from SteamIDs + + :param server_steam_ids: a list of steamids + :type server_steam_ids: list + :return: map of ips to steamids + :rtype: dict + + Sample response: + + .. code:: python + + {SteamID(id=123456, type='AnonGameServer', universe='Public', instance=1234): '1.2.3.4:27060'} + """ + resp = self.steam.unified_messages.send_and_wait("GameServers.GetServerIPsBySteamID#1", { + "server_steamids": server_steam_ids, + }, timeout=30) + + if resp is None: return None + + return {SteamID(server.steamid): server.addr for server in resp.servers} + + def get_steamids_from_ip(self, server_ips): + """Resolve SteamIDs from IPs + + :param steam_ids: a list of ips (e.g. ``['1.2.3.4:27015',...]``) + :type steam_ids: list + :return: map of steamids to ips + :rtype: dict + + Sample response: + + .. code:: python + + {'1.2.3.4:27060': SteamID(id=123456, type='AnonGameServer', universe='Public', instance=1234)} + """ + resp = self.steam.unified_messages.send_and_wait("GameServers.GetServerSteamIDsByIP#1", { + "server_ips": server_ips, + }, timeout=30) + + if resp is None: return None + + return {server.addr: SteamID(server.steamid) for server in resp.servers}