Awesome
C# tracker
This code belongs to the RAGE project and sends analytics information to a server; or, if the server is currently unavailable, stores them locally until it becomes available again.
After a game is developed, a common need is to know how the players play, what interactions they follow within the game and how much time they spend in a game session; collectively, these are known as game analytics. Analytics are used to locate gameplay bottlenecks and assess game effectiveness and learning outcomes, among other tasks.
Installation
- Clone the repository with
git clone --recursive -j8 git://github.com/e-ucm/dotnet-tracker.git
- Include projects into your solution or open the existing solution found in the root of the repository:
- If you already have the
AssetManager
project, ignore it, if not, include it into your solution. - Include
TrackerAsset
and make sure you referenceAssetManager
fromTrackerAsset
- Reference
AssetManager
andTrackerAsset
into your main project.
- If you already have the
- Create a new
TrackerAsset
instance and start configuring it by creating a new instance ofTrackerAssetSettings()
:- Host: If storage type is set to
TrackerAsset.StorageTypes.net
, this should contain the hostname or IP for the analytics server - Secure: If the server uses a secure connection (HTTPS), set it to
true
. - Port: This should have the port of the analytics server. By default, port
80
(HTTP) is used. - BasePath: Lets you set the route for the api path of the analytics server. Usually set to
/api
. - StorageType: can be
TrackerAsset.StorageTypes.net
, to send traces to a server, oTrackerAsset.StorageTypes.local
, to store them locally. - TraceFormat: the format of the traces. Can be
TrackerAsset.TraceFormats.xapi
(recommended),TrackerAsset.TraceFormats.csv
orTrackerAsset.TraceFormats.json
(Deprecated). If you want to use a format other than xAPI, you should setTrackerAsset.Instance.StrictMode = false
. - TrackingCode: If storage type is set to
TrackerAsset.StorageTypes.net
, this is the tracking code identifying the game - BackupStorage: If true, creates a traces backup file in the filesystem where the game is being run, formated in CSV
- LoginEndpoint: Endpoint for login. If not specified,
"login"
. - StartEndpoint: Endpoint for start. If not specified,
"proxy/gleaner/collector/start/{0}"
. - TrackEndpoint: Endpoint for track. If not specified,
"proxy/gleaner/collector/track"
. - UseBearerOnTrackEndpoint: If true, it will use Bearer on track endpoint auth.
- Host: If storage type is set to
- Set up a bridge for creating the connections with the server.
- Send traces
<b>Note</b>: The traces file are saved in the path specified by the Bridge.
Usage Example
Using the tracker is a really simple proccess. Below you will find some examples of how to setup and use the tracker.
Synchronous or asynchronous tracking
The C# tracker can work both synchronously (blocking until each request finishes; this may make your game stutter) and asynchronously (sending tracking data in background). This behavior can be configured here.
To use a tracking mode, you only need to enable its corresponding precompiler tag (SYNC
or ASYNC
), commenting out (with //
) the mode that you do not want to use:
#define ASYNC
//#undef ASYNC
By default (as seen above), the tracker operates in asynchronous mode.
Tracker access and instatiation (synchronous)
First, you need to create and manage an instance. You have two ways for doing this.
TrackerAsset
has an singleton instance if you want to use it.- Or (not recommended) you can create an instance via
new TrackerAsset()
.
// You can use Tracker via Singleton:
TrackerAsset.Instance.Settings = new TrackerAssetSettings();
TrackerASset.Instance.Bridge = new Bridge();
TrackerAsset.Instance.Start ();
TrackerAsset.Instance.Alternative.Selected("AlternativeID", "SelectedAnswer");
TrackerAsset.Instance.Flush();
//You can create your own Tracker instance and manage it yourself.
TrackerAsset player2tracker = new TrackerAsset();
player2tracker.Settings = new TrackerAssetSettings();
player2tracker.Bridge = new Bridge();
player2tracker.Start ();
player2tracker.Alternative.Selected("AlternativeID", "SelectedAnswer2");
player2tracker.Flush();
Tracker configuration
As previously explained in installation, tracker needs to be configured. There are some specific parameters that are needed to set up as Host
and TrackingCode
, and the rest of them are optional.
String domain = "https://rage.e-ucm.es/";
TrackerAssetSettings tracker_settings = new TrackerAssetSettings()
{
Host = domain,
TrackingCode = "OBTAINED_FROM_SERVER",
BasePath = "/api",
Port = 334,
Secure = domain.Split('/')[0] == "https:",
StorageType = TrackerAsset.StorageTypes.net,
TraceFormat = TrackerAsset.TraceFormats.xapi,
BackupStorage = true,
LoginEndpoint = trackerConfig.getLoginEndpoint() ?? "login",
StartEndpoint = trackerConfig.getStartEndpoint() ?? "proxy/gleaner/collector/start/{0}",
TrackEndpoint = trackerConfig.getStartEndpoint() ?? "proxy/gleaner/collector/track",
UseBearerOnTrackEndpoint = trackerConfig.getUseBearerOnTrackEndpoint()
};
TrackerAsset.Instance.Settings = tracker_settings
Bridge Implementation
As in the rest of the assets of the RAGE projects, communication is made using a repository of interfaces called Bridge
. This Bridge
implements interfaces for managing the File System, or for sending Web Requests. The use of the bridge allows us to provide a platform-independant system: supporting a different platform is just a matter of changing the bridge. If you want your tracker to be able to connect to an Analytics server, you have to use or implement a bridge for your platform that implements the interface IWebServiceRequest
, for being able to make Logs implement ILog
, and for accessing File System use IDataStorage
. For more information see the asset manager
Once you have a Bridge
, you just need to add it to the Tracker
.
//Setting the Bridge into the Tracker
TrackerAsset.Instance.Bridge = new Bridge();
Tracker Login and Start (synchronous)
The Login
and Start
methods are synchronous: your game will block until an answer is received, or a timeout or other network error ends the request. Make sure to display a suitable indication of what is going on so that players are not surprised by the (typically very short) lack of responsiveness.
Tracker Login
Tracker Login is not always necessary. If you are a developer, and you are logged into the Analytics server as a developer, you will receive traces regardless of whether players have logged in or not (however, the traces will not contain any user login information). If you are a teacher, and you want to see traces in your activities, you can configure the activity to allow anonymous users.
If you are a teacher and you want to use logged-in students, you have to add the students to the class and then ask them for credentials into your game and log them into the system using TrackerAsset.Instance.Login(String username, String password)
function.
//Log in the student BEFORE starting the tracker; you can also retrieve this from, say, a configuration file in the filesystem
String username = "student", password = "123456";
TrackerAsset.Instance.Login(username, password);
Tracker Start
To request current actor information from the server you have to start the tracker. After this, actor information will be appended to all generated traces. To start the tracker you just have to call the TrackerAsset.Instance.Start()
//Start the tracker before sending traces.
TrackerAsset.Instance.Start();
Tracker Login and Start (asynchronous)
To use the tracker asynchronously, you should first enable the ASYNC precompiler tag, as described above. This way, traces will be sent asynchronously.
Start and Login have been maintained both sync and async (this last one will only work if tracker has ASYNC tag enabled). You may also use the specific methods LoginAsync and StartAsync. Depending on your code you might want to use one or the other.
Tracker LoginAsync
Tracker LoginAsync is not really necessary. If you are a developer, and you're logged into the Analytics server as a developer, you're going to receive traces either the player has logged or not. If you're a teacher, and you want to see traces in your activities, you can configure the activity to allow anonymous users.
If you are a teacher and you want to use logged students, you have to add the students to the class and then ask them for credentials into your game and log them into the system using TrackerAsset.Instance.LoginAsync(String username, String password, Action<Boolean> callback)
function. The LoginAsync method uses an Action as third parameter that will be used to notify when the login attempt has finished and whether it was a success or not.
//Log in the student BEFORE starting the tracker
String username = "student", password = "123456";
TrackerAsset.Instance.LoginAsync(username, password, logged => {
if(logged){
// Code for when the login is successful
} else {
// Code for login failed
}
});
Tracker StartAsync
For requesting the actor to the server you have to start the tracker. This way actor is appended to the traces when generated. For starting the tracker you just have to call the TrackerAsset.Instance.StartAsync()
function.
//Start the tracker before sending traces.
TrackerAsset.Instance.StartAsync(() => {
// Code to be executed after start
});
Detailed Feature List
- Different storage types:
net
: sends data to a trace-server, such as the rage-analytics Backend. If set, a hostname should be specified via thehost
property.local
, to store them locally for later retrieval. Un-sent traces are always persisted locally before being sent through the net, to support intermittent internet access.
- Different trace formats:
csv
: allow processing in MS Excel or other spreadsheets. Also supported by many analytics environments.json
: especially intended for programmatic analysis, for instance using python or java/javascript orxapi
: an upcoming standard for student activity. Note that, if the tracker's storage type isnet
it is required to use thexapi
trace format since the rage-analytics Backend expects xAPI Statements. The xAPI tracking model that the backend expects is composed of Completables, Reachables, Variables and Alternatives. Notice that if you want to use a format other than xAPI, you should setTrackerAsset.Instance.StrictMode = false
.
- Tracker messages can be displayed in the Unity console by setting the
Debug
property - Uses Unity's in-built facilities to handle connections, files and timing.
User Guide
The tracker requires (if net
mode is on) the RAGE Analytics infrastructure up and running. Check out the Quickstart guide and follow the developer
and teacher
steps in order to create a game and setup a class. It also requires a:
- Host: where the server is at. This value usually looks like
<rage_server_hostmane>/api/proxy/gleaner/collector/
. The collector is an endpoint designed to retrieve traces and send them to the analysis pipeline. - Tracking code: an unique tracking code identifying the game. This code is created in the frontend, when creating a new game.
The tracker exposes an API designed to collect, analyze and visualize the data. The API consists on defining a set of game objects. A game object represents an element of the game on which players can perform one or several types of interactions. Some examples of player's interactions are:
- start or complete (interaction) a level (game object)
- increase or decrease (interaction) the number of coins (game object)
- select or unlock (interaction) a power-up (game object)
A gameplay is the flow of interactions that a player performs over these game objects in a sequential order.
The main typed of game objects supported are:
- Completable - for Game, Session, Level, Quest, Stage, Combat, StoryNode, Race or any other generic Completable. Methods:
Initialized
,Progressed
andCompleted
. - Accessible - for Screen, Area, Zone, Cutscene or any other generic Accessible. Methods:
Accessed
andSkipped
. - Alternative - for Question, Menu, Dialog, Path, Arena or any other generic Alternative. Methods:
Selected
andUnlocked
. - TrackedGameObject for Enemy, Npc, Item or any other generic GameObject. Methods:
Interacted
andUsed
.
Completable
Usage example for the tracking of an in-game quest. We decided to use a Completable game object for this use-case as the most suitable option:
// Completable
// Initialized
TrackerAsset.Instance.Completable.Initialized("MyGameQuestId", Completable.Quest);
//...
// Progressed
TrackerAsset.Instance.Completable.Progressed("MyGameQuestId", Completable.Quest, 0.8);
//...
// Progressed
bool success = true;
TrackerAsset.Instance.Completable.Completed("MyGameQuestId", Completed, success);
Accessible
Usage example for the tracking the player's movement through some in-game screens and skipping the Intro
cutscene:
// Accessible
// The player accessed the 'MainMenu' screen
TrackerAsset.Instance.Accessible.Accessed("MainMenu", Accessible.Screen);
//...
// The player skipped a cutscene
TrackerAsset.Instance.Accessible.Skipped("Intro", Accessible.Cutscene);
Alternative
Usage example for the tracking the player's choices during a conversation:
// Alternative
// The player selected the 'Dan' answer for the question 'What's his name?'
TrackerAsset.Instance.Alternative.Selected("What's his name?", "Dan", Alternative.Question);
//...
// The player selected 'OK' for the question 'Do you want it?'
TrackerAsset.Instance.Alternative.Selected("Do you want to start right now?", "OK", Alternative.Question);
//...
// The player unlocked 'Combat Mode' for the menu 'Menues/Start'
TrackerAsset.Instance.Alternative.Unlocked("Menues/Start", "Combat Mode", Alternative.Menu);
Tracked Game Object
Usage example for the tracking the player's with a NPC villager and using a health potion (item):
// Tracked Game Object
// The player interacted with a Non Playable Character
TrackerAsset.Instance.GameObject.Interacted("NPC/Villager", TrackedGameObject.Npc);
//...
// The player used a health potion
TrackerAsset.Instance.GameObject.Used("Item/HealthPotion", TrackedGameObject.Item);
Note that in order to track other type of user interactions it is required to perform a previous analysis to identify the most suitable game objects (Completable, Accessible, Alternative, GameObject) for the given case. For instance, in order to track conversations alternatives are the best choice.
Tracker and Collector Flow
If the storage type is net
, the tracker will try to connect to a Collector
endpoint, exposed by the rage-analytics Backend.
More information about the tracker can be found in the official documentation of rage-analytics.