UnrealSmall.gif (411 bytes)
Unreal Technology

Resources
Announcements
Downloads
Community

Unreal Tournament
Home Page
Known Issues and Bugs
Performance Tweaks
Running UT  Servers

Console Commands
AI

Licensing
Partners
Features
Licensing FAQ
Company Info

Level Design
UnrealEd Quick Notes
Overview of Zones

Programming
Mod Development
UnrealScript Reference
UnrealScript Black Magic
Networking Architecture
Server Querying
Objects in C++
Engine Redistribution
Localization
True-type Fonts

Other Content Creation
Package Files
Package Commandlet
Audio
Textures
Fire & Water
Music
Mesh LOD Tech
Mesh 3ds2unr Tool
Skeletal Animation

Unreal 1
Unreal 1 Server Tips
Unreal URL's
Master Servers
Console Commands
AI





unrealcomposite.jpg (19818 bytes)

IpServer Package for Unreal v1.0

Brandon Reinhart
Epic MegaGames, Inc
brandon@epicgames.com
http://www.epicgames.com/

Audience:

  1. UnrealScript Programmers and Unreal Technology Licensees.
  2. Programmers developing third party information gathering tools.
  3. Server administrators interested in creating a master server uplink.
Last Updated: 09/14/98

References to Unreal's C++ code is only relevant to Unreal licensees who have access to Unreal source.

Overview

"I don't know what to do. I need a rendezvous."
- Kraftwerk, Computer Love
Communication with other servers and systems is integral to the online gaming environment. Applications like GameSpy, QStat, and PingTool allow players a simple central application from which to manage the massive numbers of servers world wide. In addition, as games become more mature and bandwidth more available, the ability to link multiple servers in a network becomes more attractive.

The IpServer package for Unreal is provided for programmers interested in communicating with the Unreal game server, or programmers interested in expanding the information available through such communication. IpServer makes the underlying UDP architecture more or less transparent and allows an easy interface for communicating to external systems.

One of the goals in developing the IpServer query interface was to harness the power of Unreal's object oriented architecture. As such, it is possible to query for nearly any game, level, or player information Unreal or Unreal derivatives provide.

Another goal was to make integration with existing programs as easy as possible. IpServer is completely compliant with GameSpy's new query protocol. A copy of the GameSpy development docs can be obtained from Mark Surfas (mark@gamespy.com), but the majority of the protocol, as is relevant for communicating with Unreal, is documented here.

TCP & The Old Stuff

The IpDrv package has been broken up into IpDrv and IpServer. IpServer, documented here, contains all classes relevant for performing server uplinks and queries.

The old TCP versions of the Uplink and Query classes have been removed.

Master Server Uplinks with UdpServerUplink

UdpServerUplink and UdpServerQuery are the two classes in IpServer that handle master server uplinks and application queries, respectively. UdpServerUplink is instantiated when a server begins and if that server is configured for a master server uplink, it initializes the uplink and instantiates a UdpServerQuery class.

The first step in setting up the master server uplink is to configure the server. To do this, start Unreal, open the menu and go to Options::Advanced Options. A small config window will pop up. Inside the window, click on "Networking" then click on "Master Server Uplink Config" It will take a few seconds for the IpServer class to load. When the class is loaded, the menu will expand allowing you to set the following options:

DoUplink [true/false]
If DoUplink is true, then Unreal will attempt to connect to the master server. If false, it will not. Note that you must attempt to connect to a master server in order for the game server to answer queries. This can be changed by overriding the PostBeginPlay() function in UdpServerUplink.
Default: false

MasterServerAddress [IP Address/Domain Name]
This is the internet address of the master server. It can be specified as either a fully qualified domain name or as a dotted IP address. If empty, the default master server for the game server's region will be used.
Default: none

MasterServerPort [integer port num]
This is the port that the master server is listening for heartbeats on. For GameSpy, the master server listen port is 27900.
Default: 27900

QueryPort [integer port num]
This is the port that the game server will listen for queries on.
Default: 8777

UpdateMinutes [integer time in minutes]
This is the period of time, in minutes, that the game server will send a heartbeat packet to the master server. For GameSpy this should be 5 minutes.
Default: 5

UplinkPort [integer port num]
This is the port that the game server will bind for sending heartbeat packets to the master server. Specifiying 0 means that you do not have a port preference. A free port will then be assigned.
Default: 0

Region [int RegionCode]
This is a GameSpy code for the game server's geographical region. The default master server is also determined from this value.
Valid codes are:

0 - No Region Specified (any Region)
1 - Southeast US
2 - Western US
3 - Midwest US
4 - Northwest US, West Canada
5 - Northeast US, East Canada
6 - United Kingdom
7 - Continental Europe
8 - Central Asia, Middle East
9 - Southeast Asia, Pacific
10 - Africa
11 - Australia / NZ / Pacific
12 - Central, South America

Default: 0

Once you have configured the above options as you see fit, you are ready to start your game server. The UdpServerUplink package is automatically loaded whenever a new game server starts, so once the uplink is configured the work is done.

On the implementation side of things, UdpServerUplink is intentionally very simple. When PostBeginPlay() is called on the uplink object, it binds all appropriate ports, creates the query object, and sends out an initial heartbeat. It also sets up a timer to send heartbeat packets every UpdateMinutes * 60 seconds.

Query Service with UdpServerQuery

The core of the IpServer package is the UdpServerQuery class. When instantiated, a UdpServerQuery will listen for GameSpy Query Protocol formatted queries and respond with game information. If the game server is configured to perform a master server uplink then a query object will be spawned at the time the uplink is initialized.

Like UdpServerUplink, UdpServerQuery requires configuration prior to use. Go to the "Networking" menu as before and click on "Game Server Query" to open the configuration window. The following options are available:

AdminEmail [string 128]
This is a string identifying the email address of the game server administrator. If nothing is supplied, then nothing will be sent to the master server.
Default: none

AdminName [string 128]
This is a string identifying the organization or person running the game server. If nothing is supplied, then nothing will be sent to the master server.
Default: none

ServerName [string 128]
A name for the server. This can be anything.
Default: Another Unreal Server

ServerPort [int port num]
The port the server is running a game on.
Default: 7777
As the IpServer package develops, more user definable strings will come available. Feel free to email me with suggestions for new strings. I will not, however, be including the suggested AdminAge, AdminSex, and AdminPhoneNumber. :-)

Once the query responses are configured the setup is finished, just run a server to have the query server object answer queries.

Inside UdpServerQuery

Internally, UdpServerQuery is very simple. It binds all appropriate ports in the BeginPlay() function, which is called when the object is instantiated.

Once initialized, the UdpServerQuery is entirely event driven. It reponds to ReceivedText() events which are triggered whenever a query packet it received on the listen port.

The intercepted string is recursively parsed and answered in the ParseQuery function:

function string[240] ParseQuery(IpAddr Addr, string[240] Query, int QueryNum, out int PacketNum)

Query is the received string query. QueryNum and PacketNum are used for numbering response packets. Addr is the address of origin for the query.

ParseQuery is pretty straightforward. The intrinsic function ParseNextQuery takes a GameSpy querystring and parses out the first \key\optional_value pair. A success indicator is returned. QueryType contains the key, QueryValue contains the value, if any, QueryRest contains the remainder of the Query, and FinalPacket indicates whether the sectioned parsed is the last valid \key\optional_value pair in the Query. This is easier to understand if you know how the GameSpy Query Protocol works. (So I will briefly digress.)

--BEGIN DIGRESSION--

Each query is a series of \key\optional_value pairs. A simple query might look like:

\basic\

or

\echo\What time is it, foo?

A compound query might look like:

\basic\\info\\echo\What time is it, foo?\\players\

In the first case, ParseNextQuery() would return true. QueryType would contain "basic", QueryValue would be a null string, QueryRest would be a null string, and final packet would be true.

In the last case, ParseNextQuery() would return true. QueryType would contain "basic", QueryValue would be a null string, QueryRest would contain "\info\\echo\What time is it, foo?\\players\", and final packet would be false.

If valid strings are sent with abnormal leading or trailing characters, the abnormal characters will be ignored and discarded. For example, the query:

junkjunkjunk\basic\morestuffthat'sjunk

Would be parsed by ParseNextQuery() just like the query \basic\.

--END DIGRESSION--

If ParseNextQuery returns successfully, the path of execution switches on the QueryType. Here are possible valid queries:

\basic\
The basic query obtains the game name, game version, and server location:

\gamename\unreal
\gamever\[current version]
\location\[regional location]

The gamename is ALWAYS "unreal". This is so that querying programs can tell that the game server is, in fact, an Unreal server.

\info\
The info query obtains various important server information. Specifically, Unreal answers with:

\hostname\[server name]
\hostport\[server game port]
\hostip\[server game ip]
\mapname\[current map name]
\gametype\[current game or mod name]
\numplayers\[number of players]
\maxplayers\[max number of players]
\gamemode\openplaying

The gamemode is ALWAYS openplaying. This is to tell querying programs that the Unreal server's game can be dynamically joined. Obviously there aren't any carriage returns in the actual answer string.

\rules\
The rules query obtains rules for the current game. Specifically, Unreal answers with:

\timelimit\[time limit]
\fraglimit\[frag limit]
\MultiplayerBots\[true/false]
\ChangeLevels\[true/false]
\AdminName\[string name] *optional*
\AdminEMail\[string email] *optional*

Optional strings aren't sent if the answer would be null.

\players\
Players is used to obtain specific information on all connected players:

\name_N\[name of player N]
\score_N\[score of player N]
\team_N\[team of player N]
\skin_N\[skin of player N]
\mesh_N\[mesh of player N]

Ping and Time Playing will be added in the future. See below for more information on this response and its structure.

\status\
Status is a special query that obtains all the results of the basic, info, rules, and players queries combined.

\echo\echo_string
The echo query obtains a response that is identical:

\echo\echo_string

\secure\challenge_string
The secure query is used to verify that the server being queried is actually a legit Unreal server. The challenge_string is encrypted using a secret key and sent back:

\validate\response_string

\level_property\propname
A special query that is not in the GameSpy Query Protocol specification. This is discussed below, but the response is of the form:

\level_propname\propvalue

\game_property\propname
A special query that is not in the GameSpy Query Protocol specification. This is discussed below, but the response is of the form:

\game_propname\propvalue

\player_property\propname
A special query that is not in the GameSpy Query Protocol specification. This is discussed below, but the response is of the form:

\player_propname_N\propvalue

In addition, each packet is sent with an identifying number appended to the end:

\queryid\querynum_packetnum

Each query is assigned a unique identifier called the querynum. If the response to the query is broken up over multiple packets, each packet is numbered with a packetnum value. This is because the UDP protocol does not guarantee that packets will arrive in order. This system is detailed further in GameSpy's Query Protocol Documentation.
Example:

A client queries with \basic\ and the answer packet as \queryid\1_1 appended to the end. Another client queries with \status\ but the response is broken into multiple packets with the trailers \queryid\2_1 \queryid\2_2 \queryid\2_3 and so on.

Finally, the last packet in each response has the tag \final\ appended to it just before the \queryid\ tag. This is so that the querying application can determine how many packets are in the response.

UDP Issues and Packets

I have chosen to implement as much of IpServer in UnrealScript as possible. The idea is to make a server uplink/query system that is very extendable by third party developers and mod authors. As such, while the number of transferred packets is generally minimal, it may not always be optimal.

Here are some things to keep in mind about using IpServer:

  • UDP is an "unreliable" protocol. It doesn't check to see if packets have arrived at their destination and it doesn't resend packets that are lost.
  • UDP doesn't guarantee packet order. If you send data to another machine in seperate packets, those packets may not arrive in the order sent. Using a numbering system, like the \queryid\X_X system, to manage packet arrival.

The Property Queries

At this time, UdpServerQuery is capable of responding to three unique queries. Called the property queries, these queries allow the requesing server to obtain arbitrary member variables from certain game objects. The queries are:

\level_property\name of member variable
This query obtains a member variable from the server's current Level object.

\level_propname\propvalue

\game_property\name of member variable
This query obtains a member variable from the server's current Game object. The default behavior is to cast the Level.Game reference as a DeathMatchGame, so unmodified servers can only send members of DeathMatchGame.

\game_propname\propvalue

\player_property\name of member variable
This query obtains a member variable from each connected player's PlayerPawn.

\player_propname_N\propvalue of player N

Using the GetPropertyText method Unreal's object class provides, these queries can be used to obtain ANY non private information from the relevant objects. This can be of great use to query application authors who need information not provided by default responses but who don't want to subclass a new query server.

On the other end of the spectrum, UnrealScript programmers who are making their own mods can subclass the query server and, for example, cast the Level.Game reference as their own game type. Thus providing querying applications the ability to obtain special game information specific to the new mod.

Programmers could also take the provided Property Queries as examples to derive their own. For example, you could make an Actor property query that would use the AllActors iterator to obtain information on literally ANY actor instantiated on the game server. Obviously, significant design consideration will have to be put into how best to use such dynamic power (the potential for abuse is why a general Actor query is not included in the public release).

IpServer as a Model

IpServer serves as a good model on how to use the UdpLink package effectively. Read the code and come up with ideas for your own UdpLink derivatives. Possible ideas include:

- Linked Game Servers
(use GetPropertyText to send information on Actors to other servers)
- IRC/telnet Interfaces
(use the UdpLink or TcpLink capabilities to communicate with remote machines)
- Advanced Querying Systems
(use the query model as a guide to creating a versitile query interface for your Unreal engine game or modification)

Conclusion

IpServer will be regularly updated, but could forseeably achieve a plateau of functionality where more improvements are not necessary. The potential of the Property Queries implies that Unreal could work with future versions of querying tools with little work on either end (IpServer maintainer or query tool author). The Property Queries also set up the potential for very complex and very cool interserver relationships.

END