Querying Game Servers

Contributed by decapitator`
Querying Game Servers Querying Game Servers
  1. Introduction
    I will go thruw two diverent protocols in this tutorial just to show you the diverence in these game protocols on how to query and parse them. Since the query strings could be diverent for each game. Here is what we will be handeling:
    • Source Protocol (HL2, CS:S, etc)
    • UnrealTournament (Since I'm an UT1 freak)
  2. Getting Started
    Well to get started to query a game server you need to know how the protocol works. A good website with many info on server protocols is dev.kquery.com. Once you know what string to send to the server for information eg. for Source "����TSource Engine Query" or for UnrealTournament "\info\". We continue to the first stage on how to use UDP sockets in mIRC.
  3. Extra Notes: UDP Sockets
    UDP is a connection-less protocol, ie. you can send information via UDP to other UDP addresses without needing to connect to them first.

    UDP does not guarantee that any information you send will actually reach it's destination, ie. it isn't a reliable protocol. Also, be aware that UDP packets may not arrive in the same order as that in which they were sent. This means that you must perform your own checking to confirm that any data you sent actually reached it's destination properly.
  4. UDP Sockets in mIRC
    UDP sockets in mIRC are handeled with the '/sockudp' (/help /sockudp) command. The syntax for the command would be:
    Code:
    /sockudp [-bntkd] [bindip] [port] [numbytes] [text|%var|&binvar]

    The important parts
    • The -k switch forces the socket to stay open, this allows it to listen for data that is sent to its port via UDP. If -k is not specified, the socket is opened, the information is sent to the specified ipaddress and port, and the socket is then closed.
      This is needed so that it can send the requested info back over the connection.
    • would be the name you bind to the socket to handle it in further parts of the script.
    • , would be quite clear. This would be the IP address of the server you are trying to query.
    • this would be the query port.
      Tho remember this is not allways the same as the server port, some games allow to change the query port or its diverent by standard. For example in UnrealTournament the standard query port is server port + 1. So eg. if server port is 7777, the query port is 7778.
    • [text] this is where your query strings go we looked up at the "getting started" part of this tutorial.
    The others are not used in this tutorial if you wish to know more about them see the mIRC manual.
  5. Setting up the query
    Now we know how the '/sockudp' works lets convert it to what we want it to.
    • Source example (BOOMTOWN CS-Source #01):
      Code:
      /sockudp -k gquerysource 80.160.78.217 27301 ����TSource Engine Query
    • UnrealTournament example (jolt.co.uk - DM 1 - Deck 16][ Only):
      Code:
      /sockudp -k gqueryut 195.149.21.71 7898 \info\
    Note: These IP's might change or servers are down so this can be outdated.

    This will open an UDP socket to the server and sends it the text string.
    If you run this nothing other then opening a socket would happen since we dont have anything that handles the replie.
    If you did run it theres a chance the socket is still open, you could check for open sockets by using '/socklist' and close it if needed with '/sockclose '.

  6. Reading Data
    Reading data from UDP sockets in mIRC is done with the '/sockread' (/help /sockread) command in the 'on udpread' (/help on udpread) event. The on udpread event triggers when the server actually sends data back wich we then can use. Heres an example event.
    Code:
    on *:udpread:gquery*:{ sockread &t sockclose $sockname echo -a Had some kind of reply from the server! }
    This will read the data send by the server into a binary variable (/help Binary Variables) and close the socket.
    Note: The sockread command reads 4096 bytes by default, if the output is larger then 4096 bytes you will need to change the numbytes value in the sockread command or work your way around with a while loop of some kind.
  7. Parsing the Reply
    Ok this part might be a bit tricky, and is the hardest of it all. Parsing strings can be quite a pain in the ass if you dont know how to. First of all lets check the replie we got from the servers. Lets change our on udpread event
    Code:
    on *:udpread:gquery*:{ sockread &t ;check the replie has an actualy length so there is information if ($bvar(&t,0)) { ;echo this will echo the value of the binary variable (ASCII Values) echo -a $bvar(&t,1-) ;echo the actually text (characters) read from the socket echo -a $bvar(&t,1-).text } sockclose $sockname }

    Note: It might not echo everything from the replie, thats becouse mIRC doesnt allways know what to do with some characters, eg the \0x00 char (ASCII value 0) replied by the source servers will stop the replie in mIRC's echo after that. (see the source reply below)

    Here are the replies that I got from the two servers:
    • The source Query:
      Code:
      255 255 255 255 73 7 66 79 79 77 84 79 87 78 32 67 83 45 83 111 117 114 99 101 32 35 48 49 32 47 70 70 58 32 79 110 0 100 101 95 97 122 116 101 99 0 99 115 116 114 105 107 101 0 67 111 117 110 116 101 114 45 83 116 114 105 107 101 58 32 83 111 117 114 99 101 0 240 0 18 20 0 100 108 0 1 49 46 48 46 48 46 50 50 0 ����I.BOOMTOWN CS-Source #01 /FF: On
    • The UnrealTournament Query:
      Code:
      92 104 111 115 116 110 97 109 101 92 106 111 108 116 46 99 111 46 117 107 32 45 32 68 77 32 49 32 45 32 68 101 99 107 32 49 54 93 91 32 79 110 108 121 92 104 111 115 116 112 111 114 116 92 55 56 57 55 92 109 97 112 116 105 116 108 101 92 68 101 99 107 49 54 93 91 92 109 97 112 110 97 109 101 92 68 77 45 68 101 99 107 49 54 93 91 92 103 97 109 101 116 121 112 101 92 68 101 97 116 104 77 97 116 99 104 80 108 117 115 92 110 117 109 112 108 97 121 101 114 115 92 52 92 109 97 120 112 108 97 121 101 114 115 92 49 48 92 103 97 109 101 109 111 100 101 92 111 112 101 110 112 108 97 121 105 110 103 92 103 97 109 101 118 101 114 92 52 53 49 92 109 105 110 110 101 116 118 101 114 92 52 51 50 92 119 111 114 108 100 108 111 103 92 102 97 108 115 101 92 119 97 110 116 119 111 114 108 100 108 111 103 92 102 97 108 115 101 92 113 117 101 114 121 105 100 92 55 54 46 49 92 102 105 110 97 108 92 \hostname\jolt.co.uk - DM 1 - Deck 16][ Only\hostport\7897\maptitle\Deck16][\mapname\DM-Deck16][\gametype\Deat hMatchPlus\numplayers\4\maxplayers\10\gamemode\openplaying\gamever\451 \minnetver\432\worldlog\false\wantworldlog\false\queryid\76.1\final\
    To parse all of this you will need to find a rythem that splits the string into parts, try finding the char that splits the strings.

    Once you found them (The 0 char in csquery, and the \ (chr 92) in utquery) here. Its just a matter of a loop, or getting specified tokens. Here are two examples:
    • Source Query:
      Code:
      on *:udpread:gquerysource:{ sockread &t if ($bvar(&t,0)) { ;this will replace all \0x00 characters by '�' breplace &t 0 255 ;set a temporary variable and strip the first 7 chars since they are not needed (returns what kind of string is returned by the server) var %t = $bvar(&t,7-).text ;now we can simply use gettok on the temporary variable his value with 255 as delimiter echo -a $+(,$gettok(%t,4,255),) - server: $gettok(%t,1,255) map: $gettok(%t,2,255) } sockclose $sockname }
      Returned:
      Counter-Strike: Source - server: BOOMTOWN CS-Source #01 /FF: On map: de_dust2
    • UnrealTournament Query:
      Code:
      on *:udpread:gqueryut:{ sockread &t if ($bvar(&t,0)) { var %t = $bvar(&t,1-).text /* The string of unrealtournament is allready devided by the \'s so we can directly get the tokens. Tho be carefull unrealtournament does not allways return the same values and formats so you will need to use a bit more secure way of finding your info. This will look in the string for a token matching eg. "hostname" and then get the one after it. */ echo -a UnrealTournament - server: $gettok(%t,$calc($findtok(%t,hostname,92) + 1),92) map: $gettok(%t,$calc($findtok(%t,mapname,92) + 1),92) } sockclose $sockname }
      Returned:
      UnrealTournament - server: jolt.co.uk - DM 1 - Deck 16][ Only map: DM-Deck16][
    This should be enough to show. What you echo or message to a channel is up to you. Using diverent query strings also returns diverent info. Depending on what you need you will need to adjust the query string and the on udpread parsing parts.
  8. Finishing
    Well I think this covers the basics on how to get and use replies from game servers. You can allways add more things for example include the IP and PORT so it can be sended in the replie, make it work for more then one server, include ping, etc, etc.. Its all up to you from now on, just use your imagination.

  9. Usefull Pages
    http://www.valve-erc.com/ - Help on the Source Engine query protocol.
    http://dev.kquery.com/ - Descriptions on many diverent game protocols.
  10. Final Notes
    This tutorial is written by Jenne "decapitator" van der Meer - http://www.impulze.net/.

    I hope it was a great help to you all.

    If you feel anything is missing, or information is incorrect or incomplete please tell it to me on irc in #impulze.net or #scripting (QuakeNet).
All content is copyright by mircscripts.org and cannot be used without permission. For more details, click here.