UGH stats

Author: }TCP{Wolf
Date: March 2006 (build 1), 2006-08-07 (build 2), 2006-08-25 (build 3)
Package summary: Stats for Unreal One (requires UTF 10C or newer)

Table Of Contents

  1. Introduction
  2. How does it work?
  3. Requirements
  4. Security Precautions
  5. Installation
  6. Running
  7. Settings
  8. History

Introduction

UGH stats is a stats collector system for Unreal one. I have kicked this project off after public demand and offer the full source as freeware. It is up to other people to make use of the stats or to ask what other stats they want collected. There are limits, and I do not intend to update or work on this project very often.

How does it work?

UGH stats consists of 2 programs.

  1. A UScript mutator that collects stats and sends them over TCP/IP to a listening stats server
  2. A listening stats server, this can be any self-written program that can parse GameSpyProtocol messages using TCP/IP

The UScript mutator sends its data load at the end of every match. The stats server takes them and whatever it wants with them. The UScript mutator must be installed on all server that want stats evaluated, the listening server only needs to be installed on ONE machine somewhere in the world! You don't need one listening server per Unreal server.

For demonstration purposes and because I am such a nice person, I have written a small java program as a listening server that creates logfiles out of the received data streams. This simple server can run on any java-capable machine and can handle an infinite number of attached Unreal servers.

Requirements

UScript mutator

Any Unreal/UT that runs UTeamFix 10C or newer.

Why only UTF 10C and newer? What if I want to run EDM!

Short answer: I don't care, you get all this for free so don't complain!

Long answer:
I know that some people prefer one over the other, although what many people have continuously failed to realize is, that EDM and UTF are not competing to one another. As a matter of fact there is EDM code in UTF and there are also UTF code parts in EDM. WOW surprised?

The 2 things you should understand are, that first off, EDM and UTF have different goals in their original design. That was also why the mods could not be merged. The 2nd, and much more important fact to note is, that the original Unreal base classes are so flawed and limited in their abilities, that it would take very bad programming approaches and a lot of effort to make it work without UTF 10. Both EDM and UTF have so far improved the engine with many more basic features that it would be a shame to throw these features away.

I'm pretty sure Smartball could write an equal mutator for EDM with ease, but if you ask him if he'd do it, you would probably get the same reply as his away message on AIM... and who could blame him :P

Listening Server

The listening server can be any standalone server program that was written to parse GameSpyProtocol type messages over TCP/IP.

For ease of getting started, I provide one simple java server called "netecho". It requires a java virtual machine to run and write access to the directory it runs in. netecho will put all the data it receives into text logfiles, in pretty much the same way it receives them from a server. These logfiles can be parsed by scripts etc...

It would be possible to not write any logfiles at all but to take the data and put it in a database right away. You can write your own listening server in whatever programming language you desire to do the task.

Why even bother with writing logfiles with a java program? Well, Unreal can write logfiles too, but they are always UNICODE and appending is not possible. With an outside program, you are free to program whatever you want whereas Unreal has its limits. Thus, the interface on the UScript side was to be made as simple and as versatile as possible. That's exactly the result. The mutator transmits its data, what you do with it then, is entirely up to you!

Security Precautions

The UScript and the listening servers were designed for simplicity and efficiency - not security. You are strongly advised to strictly firewall filter the port you run the listening server on and explicitely allow ONLY those IPs to contact it of which you know exactly Unreal servers are running at.

Installation

Installing the mutator

Put the files UGH.int and UGH.u into your Unreal servers' system diretctory/ies - make as many copies as you have system directories from which you have servers running. Do NOT add UGH to server packages!

Installing the listening server (netecho)

If you write your own serverprogram, you will know yourself what todo to run it, so this section will deal with the cheap netecho java server.

Install a modern java runtime environment, you can get one from java.sun.com. The JVMs exist for numerous operating systems, including Linux, Solaris, Windows etc etc...

Then just unzip all the netecho files in some directory and you are done.

Running

Running the mutator

Start your Unreal server with the additional mutator UGH.UGHstats.

Example (one mutator):
Unreal.exe DMElsinore?Game=UTeamFix.TeamGameFix?mutator=UGH.UGHstats -server log=server.log

Remember that if you already run another mutator, just add the new mutator with a comma separated, for example:
Unreal.exe DMElsinore?Game=UTeamFix.TeamGameFix?mutator=UTFmut_jbpfatboy.jbpfatboy,UGH.UGHstats -server log=server.log

Running netecho

Assuming you have only netecho at your disposal (*cough*) here is how to run it.

Make sure your java CLASSPATH includes the current directory - that would be the dot
.
- otherwise you will get a class not found error when trying to run it. I added a small batch file called cp.bat for Windows machines, which you can execute to TEMPORARILY add the current directory to the class path. If you use it you will have to re-use it every time you open a new DOS-box to run netecho. It's better to permanently add the dot to your classpath using the computer environment settings.

If, when trying to start netecho, you get a java.lang.UnsupportedClassVersionError error, this means that your java virtual machine is older than the compiled code was created for. You can try to recompile the sources using the command javac netecho.java to get executable binaries for your virtual machine then. If this does not help, get a newer java virtual machine from the sun site!

Go to your console, or a command prompt, get yourself into the directory where you unzipped all the netecho files into, and start the program with the following parameters indicated in [brackets]:
java netecho [port] [delim] [delimreplacement] [serverdatakey] [mapdatakey]

Replace everything inside [brackets] with meaningful values, only the last 2 are optional, here is what all the parameters mean:

port: is the network port the program will listen for incoming connections.
delim: is the data/key delimeter (or separator) character which separates a key (identifier) from its value (GameSpy uses the backslash btw). What you put here will be used in the logfiles netecho creates.
delimreplacement: should the data contain any [delim] characters, of course this would screw up the data evaluation. So, the program will replace any [delim] characters found inside data with the character you want.
serverdatakey: OPTIONAL, defaults to shortname - this is which data netecho looks for as part of the filename for logfiles (see below...)
mapdatakey: OPTIONAL, defaults to mapname - another piece of data netecho looks for in the datastream to make up the log filename (see below...)

Netecho's procedure

I will now show an example session of netecho. Assuming it and java was installed properly... This is how your command prompt could look like after 2 maps have run on your unreal server...

netecho test run over 2 maps

In this example, I have run the netecho using the comma as key/data separator (delimeter) and the dot (.) as replacement should the data contain any accidental commas. I have played for 2 maps on my server, maps being Healpod and Burak, note that the filename here contains the real map filename, not the mapname, because I also used mapfilename as data key instead of the default mapname.

Now... these are the logfiles that resulted from the test-run:
20060325_213324_fuggs_DMHealPod.log
20060325_213759_fuggs_DM-Burak.log

Easy to see, the 2 games were some team games with a timelimit of 60 minutes and a scorelimit (though it says fraglimit - an old Epic/Gamespy misconception) of 30. There were 2 teams of red and blue and the game type is displayed as Infiltration Team Game, so it would appear some mod was played. With some sharp looking, you will also see the number of teamkills, score, frags, deaths etc of every participating player and if it was a HUMAN player or a computer controlled one (bot).

Settings

UGHstats UScript mutator

The settings of the UScript mutator can be found here:

UGHstats Configuration

The associated ini file is called "UGHstats.ini". Here is the example ini file that is equivalent to the settings shown in the screenshot:
UGHstats.ini

SettingMeaning
bNoEmptyReport If true, Server will report only games that actually took place. If false, server will report ANY game that ends.
Games where the map is switched by an admin are never reported (because 'EndGame() event does not occur').
'Empty' reports are considered those when maps had no players in them, or too few to get the map started (Tournament Mode where players have to wait or click ready and map switched before game started...)
bReportBasic Report Game name, version, client minimal version and server location.
bReportBots If enabled, computer controlled players will be reported like normal players. A TYPE information is added, of course, so the stats tell you if a human player or a bot was reported
bReportInfo Report hostname, short name, game type, number of players etc... you will not want to turn this one off...
bReportPlayers Should always be true, since you want stats on players after all... right? :P
bReportRules Report Scorelimit, Timelimit, Admin Email and a few other infos that you probably want to know....
bReportSpecs If true, report spectators at the end of a game too. While they will not have score (unless they played and then went into spec mode during game) it may be of interest to you to see who spectates whom when...
bReportUTFadditions I would leave this on, even if the only benefit is to see the map FILE NAME of the map that is played! Personally I always use the file name instead of a map title (mapname) to identify a map, because it is more reliable.
STATSserver Contains the IP address or DNS name of your stats listening server (e.g. where netecho is installed) - note: the stats server should be fast to contact so don't run it half a roundtrip of the globe away from the Unreal server(s) you are logging!
STATSserverPort The port of your statsserver to contact.

Detailed information on the reports

NOTE: Information marked in itallic is used by netecho internally by default.

Always reported - regardless of settings

NOTE: Replace [num] with a digit number from 0 to 3.

KeyValue
maxteams(Reported in Team Games only) maximum number of teams, usually a value between 2 and 4 inclusive
maxteamsize(Reported in Team Games only) maximum size a team is allowed to have - for example 8
teamscore_[num](Reported in Team Games only) The total score of this team
teamsize_[num](Reported in Team Games only) The size of this team
teamname_[num](Reported in Team Games only) The human readable name for the team, usually Red, Blue, and so on, but may carry other team names such as Dessert or Jungle if you play Infiltration....

bReportBasic

KeyValue
gamenameunreal for Unreal (static text), UT?
gameverEngine version, e.g. 224
mingameverminimum version clients must have to join server, usually value is 224 for Unreal, 436 for UT
locationlocation of server, coded as a number (0=global)

bReportInfo

KeyValue
hostnameThe server name as given in the network settings (default is Another Unreal Server)
shortnameThe SHORT name of the server as given in the network settings.
hostportServer port - default 7777
hostip(Disabled by IpDriver) the host's IP address - a rather useless information because you already KNOW the server's IP address anyway because it just connected to your stats server when it sends this info...
mapnameThe map name as in title - meaning, this map name is the name the author gave it, NOT the filename! Example: Sinfonia (not: DMSinfonia)
gametypeThe game type which was running, e.g. TeamGame
numplayersNumber of players in game the moment it ended - Example 8
maxplayersThe maximum number of players that would have been allowed in game - Example 12
gamemodeopenplaying (Static text by IpDriver)
gameverServer Unreal Engine version running, e.g. 225
mingameverSame as in the basic report, minimum client patch somebody needs to join the server, usually 224

bReportBots / bReportPlayers / bReportSpecs

NOTE: Replace [num] with a digit, counting starts at 0, highest number is number of reported players -1.
NOTE 2: Do not mix up Frags and Score! This is an old debate but my personal view is that frags are the number of KILLS which cannot decrease if you die! Still, that is exactly what Epic has labelled what in reality is a reflection of your overall performance: the Score! UTF will report both Frags and Score seperately as seen on its scoreboard, with exactly the same meaning: Frags are the number of kills the player scored (excluding teamkills, of course), whereas score is what counts for total! You cannot lose a frag by suiciding, for example, which is what Epic has tought us...

KeyValue
player_[num]Name of player number [num] - ASCII signs have been cleared!
admin_[num](Only reported for human players) either true or false, indicating if the player was logged in as administrator when the game ended.
spectator_[num](Only reported for human players) either true or false indicating if the player was a spectator at game end (always false if bReportSpecs is false)
type_[num]human or bot indicating player was a human player or computer controlled
score_[num]The player's score (in violation of GameSpy's standard, which stores the score in frags_[num])
frags_[num]The player's kills amounted (in violation of GameSpy's standard, which reports the player's SCORE here - GameSpy has no report for frags=kills)
deaths_[num]Number of times player has died
suicides_[num]Number of times player has committed suicide - in UTF, a suicide is if you kill yourself by typing 'suicide', if you kill yourself with a weapon without any nearby enemy, and if you kill yourself with a weapon and have a negative score!
timeinseconds_[num]Time in seconds the player was in game when the game has ended - NOTE: If there was a wait-time before the game started, you can NOT use this time value to properly calculate Frags per Second - well you can, it will still be close :P
teamkills_[num]Number of friendly fire kills committed by this player (only reported in team games)
team_[num]Team number the player was in (0=red, 1=blue, 2=green, 3=gold) (only reported in team games)
ping_[num]Ping of the player at game end in milliseconds. Computer controlled players (bots) will always report a zero ping.

bReportRules

KeyValue
AdminNameName of administrator as entered in network settings
AdminEMailAdministrator's email address as entered in network settings
MutatorThis tag can appear several times in a row and lists all running mutators (human names) - not working in UTF 10C at the moment
[xxxx]Mutators may add arbitrary information to the rules - not working in UTF 10C at the moment
UTeamFixVersionReports running version of UTF - not working in UTF 10C at the moment
timelimitThe timelimit in minutes (0=no limit)
fraglimitCAUTION! This is the SCORElimit. There exists no such thing as a frag/kill limit (damn Epic vocabulary...)
MultiplayerBotsalways true
bChangeLevelsalways true (due to UTF 10 license forbidding one-map servers)

bReportUTFadditions

KeyValue
mapfilenameThe actual FILENAME of a map! This is (in my opinion) more useful than a map title, because it cannot contain irregular characters, and some maps have no title at all, while they most certainly always do have a filename!
roundlimit(Only reported for standoff games) Maximum number of rounds a standoff/last man standing game is allowed to take (0=infinite)
roundtimelimit(Only reported for standoff games) Standoff round ends LATEST after this time in seconds (0=no limit)
standoffscoringrule(Only reported for standoff games) Number of points awarded per enemy kill or punished for a team kill in standoff team games (default is 2)

Netecho settings

This one should be pretty easy, because you can only use settings on startup of netecho... and the startup options have already been described further up this document where it says running.

History

Build 1 (March 2006)

  1. Initial release...

Build 2 (2006-08-07)

  1. UGHlink now has trim() function and isWhiteSpaceFunction
  2. trim() used on ping data, this cleans away spaces around the data

Build 3 (2006-08-25)

  1. bugfix: UGHlink class was not properly checking for specs (reported by Smartball)