Unity package for logging with Field Day's OpenGameData servers.
- Initial version
- Add reusable survey (19 May 2021)
- Firebase Analytics integration; Support for event constants; performance improvements (21 Sept 2022)
- Support for
game_state
anduser_data
parameters; support for sending arbitrary json asevent_data
(13 Jan 2023) - Updated survey support (4 April 2023)
- Support for
game_state
anduser_data
as arbitrary json (14 May 2024) - Support for mirroring events to a separate endpoint (21 May 2024)
- Updated surveys to support alternate layouts and branching (26 Nov 2024)
If you do not have openupm-cli
interface installed, run the following command:
$ npm install -g openupm-cli
Run the following command from the root folder of your project:
$ openupm add com.fieldday.opengamedata-unity
OGDLog
: handles communication with the database usingUnityWebRequest
OGDLogUtils
: contains various helper functions for building data strings and generating UUIDsCookieUtils
: a JavaScript plugin for handling cookies if the project is built for WebGLLogEvent
: wrapper class for the data objects that get sent throughOGDLog
OGDLogConsts
: wrapper struct for various app-level OpenGameData constants.FirebaseConsts
: wrapper struct for Firebase initialization parameters.OGDSurvey
: handles survey loading and display managementSurveyData
: outlines the data schema for survey dataSurveyPanel
: controller for the survey popupSurveyQuestionDisplay
: controller for the individual questions in a survey popup
An instance of OGDLog
can be created with the following format:
OGDLog log = new OGDLog(myAppId, myAppVersion)
myAppId
: an identifier for this app within the database (ex. "AQUALAB")myAppVersion
: the current version of the app for all logging events
To send a user id along with every event, call OGDLog.SetUserId(userId);
To reset application-level constants, call OGDLog.Initialize(appConsts);
To log an event, you can do so in one of three ways.
You can do so with a series of function calls.
m_Logger.BeginEvent("eventName");
m_Logger.EventParam("param1", 2); // you can set integer parameters...
m_Logger.EventParam("anotherParam", 4.5f) // floating point parameters...
m_Logger.EventParam("someStringParam", "blah"); // string parameters...
m_Logger.EventParam("isDoingStuff", true); // and boolean parameters
m_Logger.EventParamJson("subObject", "{\"someSubObjectField\":5}");
m_Logger.SubmitEvent(); // this will then submit the event.
You can also write this using an EventScope
object.
using(EventScope evt = m_Logger.NewEvent("eventName")) {
evt.Param("param1", 2); // you can call .Param on the EventScope directly.
evt.Param("anotherParam", 4.5f);
evt.Param("someStringParam", "blah");
evt.Param("isDoingStuff", true);
evt.Json("subObject", "{\"someSubObjectField\":5}");
} // upon exiting this block, the event will be automatically submitted
You can also specify the parameter JSON manually. This will allow you to send an arbitrary JSON object, provided it is valid.
m_Logger.Log("eventName", "{\"param1\":502}"); // send in a string
m_Logger.Log("eventName", OGDLogUtils.Stringify(mySerializableObject)) // you can also stringify objects serializable by Unity's default serializer.
For backwards compatibility, you can send events using a LogEvent
object, which takes the following arguments:
data
: a<string, string>
dictionary of data values for the given eventcategory
: an enum or string value to represent the given event type
Once a LogEvent
object is constructed with the given data, it can then be passed into OGDLog
with the Log()
function.
This will then log it using a sequence of calls similar to those listed in the previous section.
To set the shared game_state
parameter, you can do so in one of two ways.
m_Logger.BeginGameState();
m_Logger.GameStateParam("shared1", 2);
m_Logger.GameStateParam("anotherName", "no-job");
m_Logger.GameStateParamJson("shared2", "{\"somethingElse\":5}");
m_Logger.SubmitGameState();
You can also using a GameStateScope
similar to how the EventScope
functions.
using(GameStateScope scope = m_Logger.OpenGameState()) {
scope.Param("anotherName", "some-job");
scope.Param("shared1", 467);
scope.Json("shared2", "{\"somethingElse\":5}");
}
Finally, there is a GameState
method to set the game_state
to an arbitrary JSON-formatted string.
m_Logger.GameState("{\"param1\":502}");
The shared user_data
parameter behaves similarly to the game_state
parameter, with
a nearly identical syntax, swapping GameState
for UserData
in method names.
m_Logger.OpenUserData()
m_Logger.BeginUserData()
m_Logger.UserDataParam(...)
m_Logger.SubmitUserData()
m_Logger.UserData(...)
Valid parameter types in OpenGameData are integer types, floating point values, bools, strings,
and StringBuilder
instances.
The default maximum size of the event parameters for a single event is 4096 characters.
The default maximum size for game_state
and user_data
is 2048 characters each.
You can reconfigure these maximum sizes by passing a OGDLog.MemoryConfig
into the OGDLog
constructor.
To send events to a Firebase Analytics project, pass a FirebaseConsts
object, or a JSON string for a FirebaseConsts
object, to OGDLog.UseFirebase()
.
This is marked as [Serializable]
in Unity, so including it as a serialized field on a MonoBehaviour
or ScriptableObject
is possible.
This will initialize Firebase Analytics logging. Once Firebase Analytics has finished initializing, future events will be logged to it.
Note: Shared parameters such as game_state
and user_data
will not be uploaded while Firebase Analytics is initializing. It is recommended to wait for the OGDLog.IsReady()
method on your logger instance to return true
before setting that shared data.
Logging to Firebase for Android or iOS will require an additional Unity package. Follow the guide here to set that up.
Note: On Android, Google Play services checking is already handled by OGDLog
.
You can mirror your OpenGameData events to a secondary endpoint by calling OGDLog.ConfigureMirroring()
with the given endpoint url as a string. You can optionally pass in an app id to use as an override for the endpoint.
OGDLog.SetDebug()
can be called to set the logger's debug flag. If set, all requests and responses associated with OpenGameData event logging will be logged to the console.
A Survey
is a series of questions asked to the player at certain moments of the game (as defined by the developer). These questions are organized into Pages
, which are displayed to the player in succession. Once the survey is completed, the results are logged using an OGDLog
instance to the survey_submitted
event.
Survey packages are .json
files. Survey packages must follow the following schema:
{
"package_config_id": "some-survey-package-id", // A unique package identifier
"surveys": [ // an array of survey objects
{
"display_event_id": "some-event-id", // event id used by the game to reference this survey
"header": "A Survey Header", // text to display at the top of the survey,
"pages": [ // array of survey pages
{
"subheader": "Some Words", // text to display at the top of this survey page, underneath the header
"items": [ // array of survey questions
{
"useVerticalLayout": false, // if set, responses will be laid out vertically (if supported)
"prompt": "This is a survey question. Can you understand it?", // the displayed question text
"responses": [ "Yes", "No", "What?" ], // array of possible responses for the player to pick between
"responseFlags": [ "said-yes", "said-no", "" ] // array of internal flags to set, corresponding to each response. used for selectively skipping pages
}
]
},
{
"type": "likert-scales", // page type. custom value, exposed for the purpose of reconfiguring layouts during OnPageLayout
"subheader": "1- Completely False, 5- Definitely True",
"skipIf": [ "said-yes", "!said-no" ], // array of internal flags. if any are set (or, if a ! character precedes it, NOT set), this page will be skipped
"items": [
{
"type": "likert",
...
}
]
}
]
}
]
}
An example asset is provided here.
An instance of OGDSurvey
must be created in order to properly handle survey display and logging. This can be instantiated using the following code:
OGDSurvey surveyManager = new OGDSurvey(mySurveyPanelPrefab, myOGDLogInstance)
This requires a reference to a SurveyPanel
prefab.
From there, a survey package can be loaded using the following methods:
surveyManager.LoadSurveyPackage(mySurveyPackageInstance); // from a SurveyPackage directly
surveyManager.LoadSurveyPackageFromString(someJsonString); // from a JSON string)
surveyManager.LoadSurveyPackageFromString(someTextAsset); // from a TextAsset containing JSON contents
To display a survey for the given display_event_id
, you can call one of these variants of the DisplaySurvey
method:
surveyManager.TryDisplaySurvey("my_event_id"); // this will attempt to display the survey with the given event id and return whether or not there was a corresponding survey to display
surveyManager.DisplaySurvey("my_event_id", ResumeGame); // this will display a survey and invoke the given callback when the survey is completed. it will invoke the callback immediately if no survey is present
yield return surveyManager.DisplaySurveyAndWait("my_event_id"); // for use in coroutines. this will attempt to display the correct survey, and will proceed once the survey is completed (or if no survey was found)
Note that you can only have one survey displayed at a time. To cancel the currently displayed survey, discarding its results in the process, call surveyManager.CancelSurvey()
.
Within the Survey/_Assets
subfolder of the package, there is a DefaultSurvey
prefab. This is a basic, but fully functional, survey panel. To customize it, you can create a Prefab Variant of this prefab, bringing it into your own project and allowing you to customize images, fonts, and the like. It's recommended you also create variants of the SurveyQuestion
and SurveyResponseToggle
prefabs for further visual customization.
Additional scripts can be attached to these prefabs to configure various animation callbacks in the SurveyPanel
script. These include:
mySurveyPanel.OnLoaded // callback for when survey data is available, prior to displaying the first page
mySurveyPanel.OpenPageAnim // if set, this coroutine will execute when a new page is being displayed
mySurveyPanel.ClosePageAnim // if set, this coroutine will execute when a new page is queued up to transition the current page out
mySurveyPanel.FinishAnim // if set, this coroutine will execute upon the final survey page being submitted
mySurveyPanel.OnPageLayout // callback for when the survey page is loading, before questions are loaded
mySurveyPanel.OnPopulateQuestion // callback for when a question is being loaded
mySurveyPanel.OnFinished // callback for when the survey is completed and closed
mySurveyPanel.OnNextButtonState // callback for when the next/finish button is completed
Note: Survey prefabs must make use of TextMeshPro
text elements to be compatible.
To update the local package, run the following command:
$ openupm add com.fieldday.opengamedata-unity
This resource provides a method for untracking the submodule and removing the necessary files.
Remember to also remove the dependency in the project's manifest.json
file.