Author: }TCP{Wolf
Date: March 2006
Package summary: Stats for Unreal One (requires UTF 10C or newer)
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.
UGH stats consists of 2 programs.
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.
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
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!
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.
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!
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.
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
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...)
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...
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).
The settings of the UScript mutator can be found here:
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
Setting | Meaning |
---|---|
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. |
NOTE: Information marked in itallic is somehow used by netecho internally by default.
NOTE: Replace [num] with a digit number from 0 to 3.
Key | Value |
---|---|
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.... |
Key | Value |
---|---|
gamename | unreal for Unreal (static text), UT? |
gamever | Engine version, e.g. 224 |
mingamever | minimum version clients must have to join server, usually value is 224 for Unreal, 436 for UT |
location | location of server, coded as a number (0=global) |
Key | Value |
---|---|
hostname | The server name as given in the network settings (default is Another Unreal Server) |
shortname | The SHORT name of the server as given in the network settings. |
hostport | Server 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... |
mapname | The map name as in title - meaning, this map name is the name the author gave it, NOT the filename! Example: Sinfonia (not: DMSinfonia) |
gametype | The game type which was running, e.g. TeamGame |
numplayers | Number of players in game the moment the it ended - Example 8 |
maxplayers | The maximum number of players that would have been allowed in game - Example 12 |
gamemode | openplaying (Static text by IpDriver) |
gamever | Server Unreal Engine version running, e.g. 225 |
mingamever | Same as in the basic report, minimum client patch somebody needs to join the server, usually 224 |
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...
Key | Value |
---|---|
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. |
Key | Value |
---|---|
AdminName | Name of administrator as entered in network settings |
AdminEMail | Administrator's email address as entered in network settings |
Mutator | This 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 |
UTeamFixVersion | Reports running version of UTF - not working in UTF 10C at the moment |
timelimit | The timelimit in minutes (0=no limit) |
fraglimit | CAUTION! This is the SCORElimit. There exists no such thing as a frag/kill limit (damn Epic vocabulary...) |
MultiplayerBots | always true |
bChangeLevels | always true (due to UTF 10 license forbidding one-map servers) |
Key | Value |
---|---|
mapfilename | The 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) |
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.