Sniper's Paradise!
IpServer Package for Unreal
Brandon Reinhart
Epic MegaGames, Inc
brandon@epicgames.com
http://www.epicgames.com/
Audience:
UnrealScript Programmers and Unreal Technology Licensees.
Programmers developing third party information gathering tools.
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 StuffThe 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 UdpServerUplinkUdpServerUplink 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: 7778 |
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.
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
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]
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]
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]
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: < /td> |
\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 PacketsI 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 |
level_property\name of member variable |
\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 ModelIpServer 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 Actorsto 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) |
Listing Your Unreal Server On The Public Master Servers
- In Unreal, open the "Advanced Options" window.
- Under "Networking / Master Server Uplink", set "DoUplink" to True. This tells UnrealServer to notify the master servers of its existance.
- Under "Advanced / Game Engine Settings / ServerActors", make sure all the appropriate master servers are listed as follows:
[0] IpDrv.UdpBeacon
[1] IpServer.UdpServerQuery
[2] IpServer.UdpServerUplink MasterServerAddress=master0.gamespy.com MasterServerPort=27900
[3] IpServer.UdpServerUplink MasterServerAddress=master.telefragged.com MasterServerPort=27500
[4] IpServer.UdpServerUplink MasterServerAddress=master.ogn.org MasterServerPort=27500
People setting up Unreal servers behind firewalls have been asking for a summary of the TCP/IP ports Unreal uses. Here goes:
- UDP 7775 and 7776 are used only for LAN games. You don't need to route them through a firewall.
- UDP 7777 is for gameplay.
- UDP 7778 is for server querying.
- UDP 7779+ are allocated dynamically for each helper UdpLink objects, including UdpServerUplink objects.
- UDP 27900 is for server querying, if you enable the master server uplink. Some master servers use other ports, like 27500.
When players try to connect to an Unreal server, they connect to port 7777 by default.
Optionally, the server administrator can specify a different game port than 7777 with the "port=" command line parameter, for example: "Unreal.exe -server port=8888".
In this case, contiguous port numbers are used for helper objects: 8888 for gameplay, 8889 for querying, 8890 for helper UdpLink objects, etc.
Multiple Servers Per Machine
Each copy of the Unreal dedicated server can serve one and only one level at a time. However, you can run multiple level servers on one machine. You may give each server a unique TCP/IP port number. If you don't specify a port number, Unreal will generate a unique one, so that multiple Unreal servers may run on a machine without any special effort. Unreal's default port number is 7777.
To specify a port, use the following kind of command line:
Unreal.exe DmFith.unr port=7778 -server
Some Windows NT servers may have more than one network card installed, and thus more than one IP address. If this is the case, you need to specify the IP address for Unreal to play on using the multihome=www.xxx.yyy.zzz parameter such as:
Unreal.exe DmFith.unr multihome=204.157.115.34
Here is a sample batch file to launch two UnrealServers:
Start \UnrealSystem\Unreal.exe DmTundra.unr?game=unreali.deathmatchgame -server port=7777
log=server1.log ini1=server1.ini
Start \UnrealSystem\Unreal.exe DmTundra.unr?game=unreali.deathmatchgame -server port=7778
log=server1.log ini1=server1.ini
Using .ini files
When you run multiple servers on one machine, and you have customized the game settings, all of the servers will use the same options, from the Unreal.ini file. In many cases, this is not what you want -- for example, if you're running a "lobby" level that is a downloable level that is played locally, you don't want it to switch levels as would be the case with a deathmatch game. To handle multiple configurations, you can tell Unreal to use a different version of the configuration file than Unreal.ini like this:
Unreal.exe DmFith.unr ini=Server1.ini
The configuration file must exist in the \Unreal\System directory.
An easy way to generate a new configuration file is to go into Unreal, set whatever multiplayer options you want, exit out, and copy the Unreal.ini file to a new filename, such as MySettings.ini.
Setting advanced server options Advanced Options / Game Settings (applies to all game types)
- AdminPassword: Administrator password; only accepted if bAllowRemoteAdmin is True.
- AutoAim: Maximum allowable auto aiming amount for helping players who aren't using MouseLook.
- bLowGore: Reduced blood.
- bClassicDeathmessages: Displays old-style death messages.
- bCoopWeaponMode: Weapons behave as in coop play: each player can get them once per life, no respawning.
- bHumansOnly: Don't allow non-humans to play, such as SkaarjTroopers.
- bLowGore: Low violence.
- bMuteSpectators: Don't allow spectators to chat with players.
- bNoMonsters: No monsters in gameplay.
- bVeryLowGore: Extremely low violence.
- Difficulty: Difficulty level, affects bots.
- GamePassword: Password required for plays to enter.
- GameSpeed: Multiplies the game speed; 1.0 means normal speed. 0.5 means half-speed, 2.0 means twice normal speed.
- MaxPlayers: Maximum players allowed in the level.
- MaxSpectators: Maximum spectators allowed in the level.
- bChangeLevels: Lets the server switch levels when the frag limit or time limit is reached.
- bHardCoreMode: Increases weapon damage by 150%.
- bMegaSpeed: Increases game speed by 150%.
- bMultiplayerBots: Causes the server to place "InitialBots" number of bots in the multiplayer game.
- FragLimit: After this number of kills, the level switches. Zero means no frag limit.
- InitialBots: Number of bots to place in the game; only affects network play if bMultiplayerBots is set.
- TimeLimit: After this amount of time, the level switches. Zero means no time limit.
Remote administration
To enable remote administration on a server:
- Run Unreal.exe.
- Open up the "Advanced Options" window (from the main menu, Options/Advanced Options).
- Open up "Game Types" / "Deathmatch Game" (or whatever type of game you want to remote-administer).
- Set the "AdminPassword" to a password, for example "MyPassword".
- Exit the game, and launch your server.
Now, you can administer your server by logging in as a player and using the administrator password using the following URL syntax:
myservername.com?password=MyPassword
You can do this from within Unreal, by typing the following console command:
open myservername.com?password=MyPassword
To send administrative commands to the server, type "ADMIN" followed by any console command, documented in the Console Commands document.
For example, to switch to a new level titled DmAriza.unr, type:
- ADMIN SERVERTRAVEL DmAriza.unr
Client downloading of files
When clients enter your server, the server sends them a list of all Unreal "packages" (binary files containing structured Unreal objects). The client then makes sure he has all of the server's packages. If he does, he immediately tries to enter the game. If he is missing one or more files, he asks the server to download them, and the server obliges by sending each file in turn, using a UDP-based sliding window protocol.
The kinds of files which are automatically downloaded include:
- *.u (class files)
- *.utx (texture files)
- *.uax (audio files)
- *.unr (map files)
- *.umx (music files)
The reason behind client-side downloading is to allow servers to be set up in a Web-like fashion: Players can hop back and forth between servers, automatically downloading and caching the levels, graphics, music, and other objects as they go.
When clients download files, the files go into the \Unreal\Cache directory, using a filename composed from their 128-bit GUID (Globally Unique Identifier) and the .uxx extension, rather than their human-readable name.
Setting Up Unreal To Play Over A Local Area Network?Microsoft Certified Systems Engineer gave us these tips for setting up TCP/IP in Windows 95 to play Unreal on a LAN. All you have to do is go to networking, add in the TCP/IP protocal and then bind it to your Ethernet card. From there, the important settings are described below:
Default Gateway: This is the computer that packets are sent to if the destination address is not on the same network. (i.e. destined for the internet in most cases) The Gateway machine is basicly your connection to the internet, and it must be configured as a router, or actually be a router itself. This only needs to be filled in if you plan on having all the machines in the LAN on the internet, and if you own enough valid IP addresses to accomadate that. If you just want to set up a lan w/o internet access, (you can still use dial up on each machine) leave the default gateway blank.
Subnet Mask: This is what determines who is on your local subnet (network) and who is not. To fully describe this, I would have to write a short book. :) As long as you have 254 computers or less, just set the subnet mask to 255.255.255.0 to avoid any problems.
IP Addresses: This really isn't that important, but the InterNIC has set aside certian blocks of addresses to use for "fake" IPs. I prefer setting all my machines up as 192.168.x.x. (where x and x can be any value from 1 to 254) Note however, that when using a subnet mask of 255.255.255.0, only the last octet of the IP address can differ.(I.E. 192.168.50.1 and 192.168.52.1 couldn't communicate, but 192.168.50.1 and 192.168.50.2 could) If for some odd reason you needed to have more than 254 machines on the same network, you could use a subnet mask value of 255.255.0.0, which would allow you to change the last two octets of your ip address, but I would reccomend against it, since communication would be too slow with that many hosts on one network. (I'll explain this if you like)
That's pretty much it. TCP/IP is a pretty difficult protocol to configure for people who don't work with it every day....hopefully these pointers should help.
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.
All logos and trademarks are properties of their respective owners.
Unreal™ is a registered trademark of Epic Games Inc.
Privacy Policy
Website by Softly
Powered by RUSH