|
IpServer Package for Unreal v1.0Epic MegaGames, Inc brandon@epicgames.com http://www.epicgames.com/ Audience:
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."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: 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 UdpServerQueryThe 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: 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 UdpServerQueryInternally, 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: 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: A compound query might look like: 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: 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: In addition, each packet is sent with an identifying number appended to the end: 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.
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:
The Property QueriesAt 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: 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:
ConclusionIpServer 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 |
|