I'm a doctor, not a mechanic

Legacy:Server Query In Perl

From Unreal Wiki, The Unreal Engine Documentation Site
Revision as of 03:56, 16 November 2002 by El Muerte TDS (Talk) (some query black magic)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Querying game servers in Perl can be useful if you want to display a server's status on a web site. You can use the following Perl snippet to do it.

Implementation[edit]

Created by Mychaeel from scratch. Feel free to use, modify and enhance. Known limitations:

  • This script expects the server's response to come as a single UDP datagram. If it doesn't, the sub's output will be truncated. A neater implementation would wait for and concatenate as many packets until the final one (marked by the string \final\ at the end of it) has been received.
  • Some enhanced error checking wouldn't hurt.

Code[edit]

use Socket;
use Sys::Hostname;


###############################################################################
#
#  serverQuery $server, [$port]
#
#  Queries an Unreal Tournament game server and returns a hash containing the
#  information returned by the server, or a hash just containing an error
#  description if the query failed.
#

sub serverQuery ($;$) {

  my $addressServerHost = shift;
  my $addressServerPort = shift;
  
  $addressServerPort = 7778
    unless defined $addressServerPort;
  
  my $protocol = getprotobyname 'udp';
  my $addressClient = sockaddr_in 0, scalar gethostbyname hostname;
  
  socket SERVER, PF_INET, SOCK_DGRAM, $protocol 
    or return (error => 'Unable to create socket');
  bind SERVER, $addressClient
    or return (error => 'Unable to bind address');

  my $addressServer = sockaddr_in $addressServerPort, inet_aton $addressServerHost
    or return (error => 'Server not found');
    
  send SERVER, '\\info\\', 0, $addressServer;
  
  my $handleRead = '';
  vec($handleRead, fileno SERVER, 1) = 1;
  select $handleRead, undef, undef, 10.0
    or return (error => 'Query timed out');
  
  my $serverInfo;
  recv SERVER, $serverInfo, 0x1000, 0
    or return (error => 'Error receiving information');
  
  close SERVER;
  
  $serverInfo =~ s/\\//;
  $serverInfo =~ s/\\final\\$//;
  
  return split /\\/, $serverInfo;
  }

Usage[edit]

The sub serverQuery expects a server address and query port as its arguments and returns a hash containing the key/value pairs of the returned information. Call it as follows:

  %serverInfo = serverQuery '66.92.238.12', 7788;

  print "Results of server query:\n\n";
  print map "$_: $serverInfo{$_}\n", keys %serverInfo;

That'll give you output along the following lines:

  Results of server query:

  gametype: CTFGame
  hostport: 7787
  gamever: 436
  mapname: CTF-XV8
  hostname: [CSHP] Strangelove 2 MotherShip
  maxplayers: 16
  minnetver: 400
  wantworldlog: false
  numplayers: 1
  maptitle: XV-8
  worldlog: false
  gamemode: openplaying
  queryid: 30.1

Interpreting the individual items is up to you.


capt. k. – Dunno if/where you want to add this, but since it wasn't mentioned: you can also use the "\\status\\" query, which returns specifics of current server activity, including timelimit, scorelimit, goalteamscore, and the name/score/team of individual players present on the server. example

Mychaeel: Good point; but I guess I'll have to change the script to receive multiple packets (as said above) for a query with a potentially lengthy result like that. Will do, at some point.

El Muerte [TDS]: and you can also combine queries in one request: \basic\\rules\ (note that a request begins and ends with a slash). Also the last query request MUST be a known request or else you won't receive anything. So if you want to get all info from a server, and the server supports team information it wise to do: \teams\\echo\. this was you will always receive \echo\. if a server is online. Also an important thing to think of is NOT to check for the \final\ is the reply. \final\ is not always returned (there are constructions where \final\ won't be returned. The best way to read stuff from a UDP is by polling an asynchrone socket.