UDN
Search public documentation:
InstrumentingGameStatistics
日本語訳
中国翻译
한국어
Interested in the Unreal Engine?
Visit the Unreal Technology site.
Looking for jobs and company info?
Check out the Epic games site.
Questions about support via UDN?
Contact the UDN Staff
中国翻译
한국어
Interested in the Unreal Engine?
Visit the Unreal Technology site.
Looking for jobs and company info?
Check out the Epic games site.
Questions about support via UDN?
Contact the UDN Staff
Collecting Game Statistics In Your Game
Document Summary: This document details the structures, functionality and procedures necessary to successful instrument your game with stats collection. Document Changelog: Initial Version by Josh Markiewicz 05/11/2009. Updated by Jeff Wilson.Overview
The idea behind statistics gathering in engine was to provide game designers with useful data captured during play sessions throughout game development. It must be flexible, fast, and exhaustive. Flexible to rapidly change with the needs of designers, fast in that it can capture lots of data in realtime without disrupting gameplay, and exhaustive for historical comparison and data mining. To that end, the system uses lightweight data structures streamed to disk with buffered I/O and versioning support. Effort was made to make sure that older files will always be readable even as the data captured or their format changes. Since a gameplay session is never the same twice, the file format has to support the streaming of data in any order. This is defined below. Once you've collected some data, head on over to the reference on using the Game Stats Visualizer.Events
All events supported initially by the engine are defined in GameStats.uci. Event IDs have been organized into logical groupings, with game specific identifiers starting above 1000. You can keep your assignment organized however you wish, making sure they are unique of course. By using the macros and events defined in this file, you can begin to record information about your play sessions. See GameStats.uci for more information on the support event types already defined.GameplayEventWriter
This class handles all the writing of the data to disk. It handles file creation, buffering, and closing. Use the various logging functions defined to record information about your playsessions. Of course you can override functionality as you wish.Starting A Log Session
StartLogging(optional float HeartbeatDelta)This function is called at the beginning of a recorded session and opens up the file for writing. A guaranteed unique and platform limitation aware filename is chosen and created in the Stats folder of your game's main directory. If the heartbeat parameter is specified, then the system will get a call to Poll() every HeartbeatDelta seconds. By default, all active player controllers positions and orientations are logged at this time. The information gathered can be extended to capture/update whatever information deemed relevant to your game. To add game stats logging to your game, your custom GameInfo class must create a new insatnce of a GameplayEventsWriter (or subclass thereof) which is responsible for logging the events. This should be done in the PostBeginPlay() function of your GameInfo subclass.
function PostBeginPlay() { local class<GameplayEventsWriter> GameplayEventsWriterClass; //Code snipped... //Optionally setup the gameplay event logger if (bLogGameplayEvents && GameplayEventsWriterClassName != "") { GameplayEventsWriterClass = class<GameplayEventsWriter>(FindObject(GameplayEventsWriterClassName, class'Class')); if ( GameplayEventsWriterClass != None ) { `log("Recording game events with"@GameplayEventsWriterClass); GameplayEventsWriter = new(self) GameplayEventsWriterClass; //Optionally begin logging here //GameplayEventsWriter.StartLogging(0.5f); } else { `log("Unable to record game events with"@GameplayEventsWriterClassName); } } else { `log("Gameplay events will not be recorded."); } //Code snipped... }
Logging Events
GameStats.uci already contains numerous useful macros for logging gameplay data. They are implemented generically so that fewer functions can fill many needs. Typically a game event identifier stored as a particular generic data type should be enough to capture intent. There are more complicated logging functions that store player position, orientation, weapons used during the event and/or other pieces of information. The point is that while a single ID and a generic container isn't much by itself, it becomes game specific, context specific, and completely up to the user how the data is interpreted later. Functions exist to properly create, find, and index various metadata (team, player, weapon, etc) for space savings within the data file. A new category, GameStats, has been assigned to the output for stats collection. You can unsuppress it in the logs to see realtime output of recorded events. In order to log an event, the appropriate function must be called in the GameplayEventWriter passing it the required information. Using the pre-defined macros in the GameStats.uci file, makes this process fairly painless. For example, to log each player kill and death event, `RecordKillEvent might be used inside the Killed() function in your GameInfo subclass.// Monitor killed messages function Killed( Controller Killer, Controller KilledPlayer, Pawn KilledPawn, class<DamageType> DamageType ) { //code snipped... if ( KilledPRI != None ) { `RecordKillEvent(NORMAL, Killer, DamageType, KilledPlayer); //code snipped... }
Ending A Log Session
EndLogging()Called at the end of the session, EndLogging() writes out the remaining footer data, validates the header, and finally closes the recording file. If this function is not called, then the file is considered invalid and cannot be read by the file readers. The EndLogging() function in UTGame contains the basic functionality for ending the stat logging process. If your game does not extend from UTGame, then you would need to add similar functionality to your GameInfo subclass.
function EndLogging(string Reason) { if (GameplayEventsWriter != None) { GameplayEventsWriter.EndLogging(); } Super.EndLogging(Reason); }
Summary
Refer to the UTGame source code for examples of how instrumenting your code should work. Instrumentation checklist:- Declaration of the gameplay stats variables in the derived GameInfo class
- Starting and stopping logging of the gameplay session
- Create an instance of a writer class during PostBeginPlay() of the derived GameInfo class
- Start logging in PostBeginPlay() or in StartMatch(), depending on the game's design
- End logging typically in the EndLogging() function
- Any custom events not included in engine must be added to the SupportedEvents array inside the derived GameplayEventsWriter class
- Be sure to include GameStats.uci in each .uc used for logging
- When including the file inside of the derived GameInfo.uc file, add it in the following way
`define GAMEINFO(dummy) `include(UTGame\UTStats.uci); `undefine(GAMEINFO)
This allows the include file to make an optimization that doesn't require accessing the WorldInfo. In order to log events in other files, just use`include(UTGame\UTStats.uci)
without the defines. The macros inside the include directive assume that WorldInfo is accessible directly. If not, the logging functions can be called directly.
- When including the file inside of the derived GameInfo.uc file, add it in the following way
- Add an entry into the game's DefaultGame.ini to tell the game what class is responsible for logging events and to enable/disable logging
[XXXGame.XXXGame] GameplayEventsWriterClassName=XXXGame.XXXGameplayEventsWriter bLogGameplayEvents=<true/false>
- Add an entry into the game's DefaultEditor.ini to specify what game stats database class to use and to setup SQL database connection information for DB upload. This is necessary for visualization of the data in the editor.
[UnrealEd.GameStatsBrowser] GameStatsDBClassname=XXXEditor.XXXGameStatsDatabase RemoteConnectionIP="XXX.XXX.XXX.XXX" ConnectionString="Provider=sqloledb;Data Source=<database name>;Initial Catalog=GameStats;Trusted_Connection=Yes" RemoteConnectionStringOverride="Data Source=<database name>;Initial Catalog=GameStats;Integrated Security=True;Pooling=False;Asynchronous Processing=True;Network Library=dbmssocn"