ValvePython / steam

☁️ Python package for interacting with Steam
http://steam.readthedocs.io
MIT License
1.05k stars 127 forks source link

[FEATURE REQUEST] ISteamMatchmakingServers.ServerRules #424

Open Kein opened 1 year ago

Kein commented 1 year ago

https://partner.steamgames.com/doc/api/ISteamMatchmakingServers#ServerRules

Old web-api has gs.a2s_rules() but it is [client]-less version and a subject to draconian rate limiters. Some older games use rules as basically ways to set up tags for games.

rossengeorgiev commented 1 year ago

https://steam.readthedocs.io/en/latest/api/steam.client.builtins.html#module-steam.client.builtins.gameservers ?

Rules you get directly from the server iirc

Gobot1234 commented 1 year ago

You can get them from the TCP connection if you want https://github.com/SteamDatabase/Protobufs/blob/master/steam/steammessages_gameservers.steamclient.proto#L101-L108

Kein commented 1 year ago

@rossengeorgiev So the old API's functionality in gs.a2s_rules is the only way to go? I'm not very knowledgeable on Steamworks eco, but I was under impression, as per docs an readme page, that old API outdated, unreliable, a lot of endpoints closed or dont work and in general, subject to very strict rate limits (being "public" API) and should not be used in favour of new steam[client] implementation.

@Gobot1234 What TCP connection you are talking about? You mean the implementation in gs.a2s_rules does not even go through Steam API?

Gobot1234 commented 1 year ago

The SteamClient connects to a TCP socket, when you fetch a game server's rules using a2s you connect to the game server's socket that can however be queried using steam using that protobuf message I linked.

Kein commented 1 year ago

@Gobot1234 I dont understand what are you saying, can you elaborate on this:

that can however be queried using steam using that protobuf message I linked.

Queried how? Also, are you saying this data is mirrored on Steam API side as well? If so I'd prefer to fetch from Steam since now all servers respond.

Gobot1234 commented 1 year ago

Queried using a unified message (see SteamClient.send_um_and_wait) I can't say for sure that this works with all servers because last I checked it didn't but I think it's a lot easier to use and I don't think it has the same rate limits as a2s

Kein commented 1 year ago

I can't say for sure that this works with all servers

It only works for server that use Rules and set them. I happen to have an old game that uses them for their server name and descriptions for whatever reason.

Queried using a unified message (see SteamClient.send_um_and_wait) I

Can you elaborate how to use it? I see for get_server_list()

 resp = self._s.send_um_and_wait("GameServers.GetServerList#1",
                                        {
                                         "filter": filter_text,
                                         "limit": max_servers,
                                        },
                                        timeout=20,
                                        )

I dont exactly know what GameServers.GetServerList#1 means, especially the #1 part but GetServerList is the part described in that protobuf template you've linked. And appID is send in the filter data so it makes some sense to me in the ned. However, with the snippet youve linked:

message CMsgGameServerRulesQueryData {
    message Rule {
        optional string rule = 1;
        optional string value = 2;
    }

    repeated .CMsgGameServerRulesQueryData.Rule rules = 1;
}

I dont understand, where is the appID? Or where is the specific server address? Or Game/SteamID? I already have a server list obtained, I just need to either query rules for each or somehow get rules together with the server query.

Gobot1234 commented 1 year ago

Use GameServers.QueryByFakeIP#1 (https://github.com/SteamDatabase/Protobufs/blob/master/steam/steammessages_gameservers.steamclient.proto#L53-L65) with fake_ip, fake_port and appid being the ip, port and appid as returned by the initial query, then pass query_type as CGameServers_QueryByFakeIP_Request.EQueryType.Query_Rules and you should get a response which returns a message (CGameServers_GameServerQuery_Response) containing the first message I linked on the rules_data attribute

Kein commented 1 year ago

fake_ip, fake_port and appid being the ip, port and appid

Weird argument name for the IP and port. I assume we supply the query port, not game port?

response which returns a message (CGameServers_GameServerQuery_Response) containing the first message I linked on the rules_data attribute

I assume the existing proto_to_dict function in steam.py can handle it or do I need to create structure describing data?

Gobot1234 commented 1 year ago

Weird argument name for the IP and port. I assume we supply the query port, not game port?

Valve:tm: I'd assume it's the query port if you have it, I only seem to get game port from GameServers.GetServerList and that works for me most of the time.

I assume the existing proto_to_dict function in steam.py can handle it or do I need to create structure describing data?

proto_to_dict shouldn't be necessary here as you should be able to use attribute access on the returned protobuf right?

Kein commented 1 year ago

with fake_ip, fake_port and appid being the ip, port and appid as returned by the initial query, then pass query_type as CGameServers_QueryByFakeIP_Request.EQueryType.Query_Rules

It wont accept str as a parameters for the query blob. I've tried using direct enum value but I got:

resp = client.send_um_and_wait("GameServers.QueryByFakeIP#1",
                                {
                                    "fake_ip": ip,
                                    "fake_port": port,
                                    "app_id": *****,
                                    "query_type": 3
                                }, timeout=10)
<MsgProto(<EMsg.ServiceMethodResponse: 147> | CGameServers_GameServerQuery_Response)>
-------------- header --
steamid: *****************
client_sessionid: -1029487077
jobid_target: 2
target_job_name: "GameServers.QueryByFakeIP#1"
eresult: 8
transport_error: 1
seq_num: 1
---------------- body --
(empty)
Gobot1234 commented 1 year ago

Whats the type of fake_ip and how are you making it? Everything else looks fine there to me

Kein commented 1 year ago

According to stam docs it wants uint one so the raw response from server list unprocessed

Kein commented 1 year ago

If you have any more ideas I'm willing to try