Skip to content

Commit 8b122bf

Browse files
authored
Merge pull request #6 from yetanalytics/custom-activities
Custom activities
2 parents 39ec9ee + 986891c commit 8b122bf

5 files changed

Lines changed: 145 additions & 78 deletions

File tree

2.49 KB
Binary file not shown.

README.md

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,17 @@ public class SetPlayerPrefs : MonoBehaviour
6161
PlayerPrefs.SetString("LRSUsernameDisplay","John Doe");
6262

6363
// Game Identity Data
64+
// This sets the Platform of the statement under context.platform
65+
// by default, the object.id (aka the Activity) will also use this as it's identifier:
6466
PlayerPrefs.SetString("LRSGameId", "http://video.games/button-clicker");
6567
PlayerPrefs.SetString("LRSGameDisplay", "Button Clicker");
6668

69+
// In addition to LRSGameId, Set the following if you'd like to override the ActivityId via playerPrefs.
70+
// Note that both LRSActivityId and LRSActivityDefinition need to be set in order for this to work:
71+
PlayerPrefs.SetString("LRSActivityId", "http://video.games/button-clicker/level/1");
72+
PlayerPrefs.SetString("LRSActivityDefinition", "Level 1 of button-clicker");
73+
74+
6775
// Session Identity Data
6876
PlayerPrefs.SetString("LRSSessionIdentifier",Guid.NewGuid().ToString());
6977

@@ -78,16 +86,18 @@ public class SetPlayerPrefs : MonoBehaviour
7886
```
7987
### Session Variable Documentation
8088

81-
|Variable Name | Description |
82-
| ----------- | ----------- |
83-
| LRSEnableUserLocation | This enables the external calls required to get user regional information packaged with the statement. This data is set in `$.context.extensions.http://ip-api.com/location` |
84-
|LRSEmail | User ID in the form of an email. Follows the [RFC 3987](https://datatracker.ietf.org/doc/html/rfc3987) specification.|
85-
|LRSAccountId | A User ID that's contained within a system. (Requires LRSHomepage to be set).|
86-
|LRSHomepage | A homepage for the LRSAccountId (Requires LRSAccountId to be set).|
87-
|LRSUsernameDisplay | A human readable username display.|
88-
|LRSGameId | A Game ID in the form of an IRI. Follows the [RFC 3987](https://datatracker.ietf.org/doc/html/rfc3987) specification.|
89-
|LRSGameDisplay| A human readable display of the game being played.|
90-
|LRSSessionIdentifier| A UUID that uniquely identifies the session being engaged with. This is something that would get set whenever the user initializes a new session.|
89+
|Variable Name | Description | Statement Fields Populated |
90+
| ----------- | ----------- | ----------- |
91+
|LRSEnableUserLocation | This enables the external calls required to get user regional information packaged with the statement. | `$.context.extensions.http://ip-api.com/location`|
92+
|LRSEmail | User ID in the form of an email. Follows the [RFC 3987](https://datatracker.ietf.org/doc/html/rfc3987) specification.| `$.actor.mbox`|
93+
|LRSAccountId | A User ID that's contained within a system. (Requires LRSHomepage to be set).| `$.actor.account.name`|
94+
|LRSHomepage | A homepage for the LRSAccountId (Requires LRSAccountId to be set).| `$.actor.account.homePage`|
95+
|LRSUsernameDisplay | A human readable username display.| `$.actor.name` |
96+
|LRSGameId | A Game ID in the form of an IRI. Follows the [RFC 3987](https://datatracker.ietf.org/doc/html/rfc3987) specification.| `$.object.id`, `$.context.platform`|
97+
|LRSGameDisplay| A human readable display of the game being played.| `$.object.definition.name.en-US`|
98+
|LRSSessionIdentifier| A UUID that uniquely identifies the session being engaged with. This is something that would get set whenever the user initializes a new session.| `$.context.registration`|
99+
|LRSActivityId| Optional ActivityID in the form of an IRI. Follows the [RFC 3987](https://datatracker.ietf.org/doc/html/rfc3987) specification.| `$.object.id`|
100+
|LRSActivityDefinition| human readable activity definition display. | `$.object.definition.name.en-US`|
91101

92102
### Setting up a Scene
93103

@@ -133,17 +143,33 @@ public class xApiIntegration : MonoBehaviour
133143

134144
// Start is called before the first frame update
135145
void Start() {
146+
// by default, SendStartedStatement can be called with no arguments and uses the configuration from PlayerPrefs to populate it's statements
147+
// Note that you can set LRSActivityId and LRSActivityDefinition to override the default activity (which is LRSGameId).
136148
publisher.SendStartedStatement();
149+
150+
// you can overload SendStartedStatement with a custom ActivityID if you wish to dynamically modify the activity.
151+
// this overrides $.object.id and $.object.definition.name.en-US):
152+
publisher.SendStartedStatement("http://video.games/clicker/level/1", "Level 1 of clicking game");
137153
}
138154

139155
// Example of something we can call externally via some object callback (Like a GUI button)
140156
public void OnButtonPress() {
157+
// similarly, with SendCompletedStatement...
141158
publisher.SendCompletedStatement();
159+
160+
// or with overrides...
161+
publisher.SendCompletedStatement("http://video.games/clicker/level/1", "Level 1 of clicking game");
142162
}
143163

144-
// Example of sending a statement only configuring the verb.
145164
void OnApplicationQuit() {
165+
// Example of sending a statement only configuring the verb.
166+
// overrides $.verb.id and $.verb.display.en-US
146167
publisher.SendStatement("http://video.games/verbs/quit", "Quit");
168+
169+
// Or if you wish to send both a custom verb and activity...
170+
// overrides $.verb.id, $.verb.display.en-US, $.object.id, and $.object.definition.name.en-US
171+
publisher.SendStatement("http://video.games/verbs/quit", "Quit", "http://video.games/clicker/level/1", "Level 1 of clicking game");
172+
147173
}
148174
}
149175
```

Runtime/LRS/Domain/Publisher.cs

Lines changed: 106 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ public Publisher(String LRSUrl, String LRSKey, String LRSSecret)
2323
private Agent formAgent() {
2424
bool hasEmail = PlayerPrefs.HasKey("LRSEmail");
2525
bool hasAccount = PlayerPrefs.HasKey("LRSAccountId") && PlayerPrefs.HasKey("LRSHomepage");
26-
if (hasEmail)
26+
if (hasEmail)
2727
{
28-
return new Agent
28+
return new Agent
2929
{
3030
mbox = "mailto:" + PlayerPrefs.GetString("LRSEmail"),
3131
name = PlayerPrefs.GetString("LRSUsernameDisplay")
@@ -65,7 +65,13 @@ private Agent formAgent() {
6565
private String nameDisplay { get { return PlayerPrefs.GetString("LRSUsernameDisplay"); } }
6666
private String gameId { get { return PlayerPrefs.GetString("LRSGameId"); } }
6767
private String gameDisplay { get { return PlayerPrefs.GetString("LRSGameDisplay"); } }
68-
68+
69+
private bool hasCustomActivityEnv { get { return PlayerPrefs.HasKey("LRSActivityId") &&
70+
PlayerPrefs.HasKey("LRSActivityDefinition"); } }
71+
72+
private String customActivityId { get { return PlayerPrefs.GetString("LRSActivityId"); } }
73+
private String customActivityDefinition { get { return PlayerPrefs.GetString("LRSActivityDefinition"); } }
74+
6975
// TODO: make this optional
7076
private String registrationIdentifier { get { return PlayerPrefs.GetString("LRSSessionIdentifier"); } }
7177

@@ -106,11 +112,11 @@ private async Task<Location> GetLocation()
106112
}
107113

108114
private async Task<Statement<Agent, Activity>> FormBasicStatement(String verbId,
109-
String verbDisplay,
110-
Agent user,
111-
String gameId,
112-
String gameDisplay,
113-
String registrationIdentifier)
115+
String verbDisplay,
116+
Agent user,
117+
String gameId,
118+
String gameDisplay,
119+
String registrationIdentifier)
114120
{
115121
Extension contextExtension = new Extension() {
116122
platformSettingsMetadata = new PlatformSettings() {
@@ -136,6 +142,15 @@ private async Task<Statement<Agent, Activity>> FormBasicStatement(String verbId,
136142
contextExtension.location = loc;
137143
}
138144

145+
String activityId = gameId;
146+
String activityDefinition = gameDisplay;
147+
148+
// if there's a custom ActivityID in the env, set activityId to that one.
149+
if (hasCustomActivityEnv) {
150+
activityId = customActivityId;
151+
activityDefinition = customActivityDefinition;
152+
}
153+
139154
// statement construction
140155
return new Statement<Agent, Activity>
141156
{
@@ -148,18 +163,7 @@ private async Task<Statement<Agent, Activity>> FormBasicStatement(String verbId,
148163
enUS = verbDisplay
149164
}
150165
},
151-
objekt = new Activity
152-
{
153-
id = gameId,
154-
definition = new ActivityDefinition
155-
{
156-
name = new LanguageMap
157-
{
158-
enUS = gameDisplay
159-
},
160-
extensions = objectDefinitionExtension
161-
}
162-
},
166+
objekt = FormActivity(activityId, activityDefinition, objectDefinitionExtension),
163167
context = new Context
164168
{
165169
registration = registrationIdentifier,
@@ -169,74 +173,113 @@ private async Task<Statement<Agent, Activity>> FormBasicStatement(String verbId,
169173
};
170174
}
171175

172-
public async Task<Statement<Agent, Activity>> StartedStatement(Agent user,
173-
String gameId,
174-
String gameDisplay,
175-
String registrationIdentifier)
176+
private async Task<Statement<Agent, Activity>> FormBasicStatement(String verbId,
177+
String verbDisplay,
178+
Agent user,
179+
String gameId,
180+
String gameDisplay,
181+
String registrationIdentifier,
182+
String activityID,
183+
String activityDescription)
176184
{
177-
return await FormBasicStatement(formVerbId("initialized"),
178-
"Initialized",
179-
user,
180-
gameId,
181-
gameDisplay,
182-
registrationIdentifier);
183-
}
185+
Statement<Agent, Activity> statement = await FormBasicStatement(verbId,
186+
verbDisplay,
187+
user,
188+
gameId,
189+
gameDisplay,
190+
registrationIdentifier);
191+
statement.objekt.id = activityID;
192+
statement.objekt.definition.name.enUS = activityDescription;
193+
return statement;
184194

185-
public async Task<Statement<Agent, Activity>> CompletedStatement(Agent user,
186-
String gameId,
187-
String gameDisplay,
188-
String registrationIdentifier)
189-
{
190-
return await FormBasicStatement(formVerbId("completed"),
191-
"Completed",
192-
user,
193-
gameId,
194-
gameDisplay,
195-
registrationIdentifier);
196195
}
197196

198197

199-
public async void SendStartedStatement()
198+
private Activity FormActivity(String activityID,
199+
String activityDescription,
200+
Extension extension)
200201
{
201-
var statement = await StartedStatement(user,
202-
gameId,
203-
gameDisplay,
204-
registrationIdentifier);
205-
var statementStr = statement.Serialize();
206-
var response = await sender.SendStatement(statementStr);
207-
Debug.Log(statementStr);
202+
return new Activity {
203+
id = activityID,
204+
definition = new ActivityDefinition
205+
{
206+
name = new LanguageMap
207+
{
208+
enUS = activityDescription
209+
},
210+
extensions = extension
211+
}
212+
};
213+
}
214+
215+
private void DebugStatements(string statement, RestResponse response) {
216+
Debug.Log(statement);
208217
Debug.Log(response.Content);
209218
Debug.Log(response.ResponseStatus);
219+
210220
}
211221

212-
public async void SendCompletedStatement()
222+
223+
public void SendStartedStatement()
213224
{
214-
var statement = await CompletedStatement(user,
225+
SendStatement(formVerbId("initialized"), "Initialized");
226+
227+
}
228+
229+
public void SendStartedStatement(String activityID,
230+
String activityDisplay)
231+
{
232+
SendStatement(formVerbId("initialized"),
233+
"Initialized",
234+
activityID,
235+
activityDisplay);
236+
}
237+
238+
public void SendCompletedStatement()
239+
{
240+
SendStatement(formVerbId("completed"), "Completed");
241+
}
242+
243+
public void SendCompletedStatement(String activityID,
244+
String activityDisplay)
245+
{
246+
SendStatement(formVerbId("completed"),
247+
"Completed",
248+
activityID,
249+
activityDisplay);
250+
}
251+
252+
public async void SendStatement(String verbId,
253+
String verbDisplay)
254+
{
255+
var statement = await FormBasicStatement(verbId,
256+
verbDisplay,
257+
user,
215258
gameId,
216259
gameDisplay,
217260
registrationIdentifier);
218261
var statementStr = statement.Serialize();
219262
var response = await sender.SendStatement(statementStr);
220-
Debug.Log(statementStr);
221-
Debug.Log(response.Content);
222-
Debug.Log(response.ResponseStatus);
263+
DebugStatements(statementStr, response);
223264

224265
}
225266

226267
public async void SendStatement(String verbId,
227-
String verbDisplay)
268+
String verbDisplay,
269+
String activityID,
270+
String activityDisplay)
228271
{
229272
var statement = await FormBasicStatement(verbId,
230273
verbDisplay,
231274
user,
232275
gameId,
233276
gameDisplay,
234-
registrationIdentifier);
277+
registrationIdentifier,
278+
activityID,
279+
activityDisplay);
235280
var statementStr = statement.Serialize();
236281
var response = await sender.SendStatement(statementStr);
237-
Debug.Log(statementStr);
238-
Debug.Log(response.Content);
239-
Debug.Log(response.ResponseStatus);
282+
DebugStatements(statementStr, response);
240283

241284
}
242285

@@ -255,13 +298,11 @@ async void SendCustomStatement(String verbId,
255298
registrationIdentifier);
256299
var statementStr = statement.Serialize();
257300
var response = await sender.SendStatement(statementStr);
258-
Debug.Log(statementStr);
259-
Debug.Log(response.Content);
260-
Debug.Log(response.ResponseStatus);
301+
DebugStatements(statementStr, response);
261302

262303
}
263304

264-
async void SendScratchStatement<TActor, TObjekt>(Statement<TActor, TObjekt> statement)
305+
async void SendScratchStatement<TActor, TObjekt>(Statement<TActor, TObjekt> statement)
265306
where TActor: IActor
266307
where TObjekt: IObjekt
267308
{
@@ -270,4 +311,4 @@ async void SendScratchStatement<TActor, TObjekt>(Statement<TActor, TObjekt> stat
270311
}
271312
}
272313
}
273-
}
314+
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "com.yetanalytics.unity-xapi-publisher",
3-
"version": "1.0.1",
3+
"version": "1.0.2",
44
"displayName": "Unity Xapi Publisher",
55
"description": "This package gives you the tooling needed to send basic statements to an LRS",
66
"unity": "2021.3",

packages.config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@
33
<package id="Microsoft.Bcl.AsyncInterfaces" version="5.0.0" />
44
<package id="RestSharp" version="108.0.1" />
55
<package id="System.Runtime.CompilerServices.Unsafe" version="5.0.0" />
6-
<package id="System.Text.Encodings.Web" version="5.0.0" />
6+
<package id="System.Text.Encodings.Web" version="5.0.1" />
77
<package id="System.Text.Json" version="5.0.0" />
88
</packages>

0 commit comments

Comments
 (0)