@m2c2kit/core 0.3.7 → 0.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.d.ts +217 -52
  2. package/dist/index.js +529 -218
  3. package/package.json +7 -7
package/dist/index.js CHANGED
@@ -815,10 +815,14 @@ class Entity {
815
815
  * @remarks Inspiration from https://stackoverflow.com/a/35361695
816
816
  */
817
817
  this.toString = () => {
818
+ let type = this.type.toString();
819
+ if (this.type == EntityType.Composite) {
820
+ type = this.compositeType;
821
+ }
818
822
  if (this.name !== this.uuid) {
819
- return `"${this.name}" (${this.type}, ${this.uuid})`;
823
+ return `"${this.name}" (${type}, ${this.uuid})`;
820
824
  } else {
821
- return `"${this.type} (${this.uuid})`;
825
+ return `"${type} (${this.uuid})`;
822
826
  }
823
827
  };
824
828
  if (options.name === void 0) {
@@ -1020,11 +1024,11 @@ class Entity {
1020
1024
  * ones. It is strongly recommended not to change this, unless you have a
1021
1025
  * special use case. Default is true.
1022
1026
  */
1023
- onTapDown(callback, replaceExistingCallback = true) {
1027
+ onTapDown(callback, callbackOptions) {
1024
1028
  this.addEventListener(
1025
1029
  EventType.TapDown,
1026
1030
  callback,
1027
- replaceExistingCallback
1031
+ callbackOptions
1028
1032
  );
1029
1033
  }
1030
1034
  /**
@@ -1042,11 +1046,11 @@ class Entity {
1042
1046
  * ones. It is strongly recommended not to change this, unless you have a
1043
1047
  * special use case. Default is true.
1044
1048
  */
1045
- onTapUp(callback, replaceExistingCallback = true) {
1049
+ onTapUp(callback, callbackOptions) {
1046
1050
  this.addEventListener(
1047
1051
  EventType.TapUp,
1048
1052
  callback,
1049
- replaceExistingCallback
1053
+ callbackOptions
1050
1054
  );
1051
1055
  }
1052
1056
  /**
@@ -1065,11 +1069,11 @@ class Entity {
1065
1069
  * ones. It is strongly recommended not to change this, unless you have a
1066
1070
  * special use case. Default is true.
1067
1071
  */
1068
- onTapUpAny(callback, replaceExistingCallback = true) {
1072
+ onTapUpAny(callback, callbackOptions) {
1069
1073
  this.addEventListener(
1070
1074
  EventType.TapUpAny,
1071
1075
  callback,
1072
- replaceExistingCallback
1076
+ callbackOptions
1073
1077
  );
1074
1078
  }
1075
1079
  /**
@@ -1087,11 +1091,11 @@ class Entity {
1087
1091
  * ones. It is strongly recommended not to change this, unless you have a
1088
1092
  * special use case. Default is true.
1089
1093
  */
1090
- onTapLeave(callback, replaceExistingCallback = true) {
1094
+ onTapLeave(callback, callbackOptions) {
1091
1095
  this.addEventListener(
1092
1096
  EventType.TapLeave,
1093
1097
  callback,
1094
- replaceExistingCallback
1098
+ callbackOptions
1095
1099
  );
1096
1100
  }
1097
1101
  /**
@@ -1107,11 +1111,11 @@ class Entity {
1107
1111
  * ones. It is strongly recommended not to change this, unless you have a
1108
1112
  * special use case. Default is true.
1109
1113
  */
1110
- onPointerDown(callback, replaceExistingCallback = true) {
1114
+ onPointerDown(callback, callbackOptions) {
1111
1115
  this.addEventListener(
1112
1116
  EventType.PointerDown,
1113
1117
  callback,
1114
- replaceExistingCallback
1118
+ callbackOptions
1115
1119
  );
1116
1120
  }
1117
1121
  /**
@@ -1129,11 +1133,11 @@ class Entity {
1129
1133
  * ones. It is strongly recommended not to change this, unless you have a
1130
1134
  * special use case. Default is true.
1131
1135
  */
1132
- onPointerUp(callback, replaceExistingCallback = true) {
1136
+ onPointerUp(callback, callbackOptions) {
1133
1137
  this.addEventListener(
1134
1138
  EventType.PointerUp,
1135
1139
  callback,
1136
- replaceExistingCallback
1140
+ callbackOptions
1137
1141
  );
1138
1142
  }
1139
1143
  /**
@@ -1147,11 +1151,11 @@ class Entity {
1147
1151
  * ones. It is strongly recommended not to change this, unless you have a
1148
1152
  * special use case. Default is true.
1149
1153
  */
1150
- onPointerMove(callback, replaceExistingCallback = true) {
1154
+ onPointerMove(callback, callbackOptions) {
1151
1155
  this.addEventListener(
1152
1156
  EventType.PointerMove,
1153
1157
  callback,
1154
- replaceExistingCallback
1158
+ callbackOptions
1155
1159
  );
1156
1160
  }
1157
1161
  /**
@@ -1164,11 +1168,11 @@ class Entity {
1164
1168
  * ones. It is strongly recommended not to change this, unless you have a
1165
1169
  * special use case. Default is true.
1166
1170
  */
1167
- onDragStart(callback, replaceExistingCallback = true) {
1171
+ onDragStart(callback, callbackOptions) {
1168
1172
  this.addEventListener(
1169
1173
  EventType.DragStart,
1170
1174
  callback,
1171
- replaceExistingCallback
1175
+ callbackOptions
1172
1176
  );
1173
1177
  }
1174
1178
  /**
@@ -1181,11 +1185,11 @@ class Entity {
1181
1185
  * ones. It is strongly recommended not to change this, unless you have a
1182
1186
  * special use case. Default is true.
1183
1187
  */
1184
- onDrag(callback, replaceExistingCallback = true) {
1188
+ onDrag(callback, callbackOptions) {
1185
1189
  this.addEventListener(
1186
1190
  EventType.Drag,
1187
1191
  callback,
1188
- replaceExistingCallback
1192
+ callbackOptions
1189
1193
  );
1190
1194
  }
1191
1195
  /**
@@ -1198,24 +1202,29 @@ class Entity {
1198
1202
  * ones. It is strongly recommended not to change this, unless you have a
1199
1203
  * special use case. Default is true.
1200
1204
  */
1201
- onDragEnd(callback, replaceExistingCallback = true) {
1205
+ onDragEnd(callback, callbackOptions) {
1202
1206
  this.addEventListener(
1203
1207
  EventType.DragEnd,
1204
1208
  callback,
1205
- replaceExistingCallback
1209
+ callbackOptions
1206
1210
  );
1207
1211
  }
1208
- addEventListener(type, callback, replaceExistingCallback) {
1212
+ addEventListener(type, callback, callbackOptions) {
1209
1213
  const eventListener = {
1210
1214
  type,
1211
1215
  entityUuid: this.uuid,
1212
1216
  callback
1213
1217
  };
1214
- if (replaceExistingCallback) {
1218
+ if (callbackOptions == null ? void 0 : callbackOptions.replaceExisting) {
1215
1219
  this.eventListeners = this.eventListeners.filter(
1216
1220
  (listener) => !(listener.entityUuid === eventListener.entityUuid && listener.type === eventListener.type)
1217
1221
  );
1218
1222
  }
1223
+ if (this.eventListeners.some((listener) => listener.type == type)) {
1224
+ console.warn(
1225
+ `game {${this.game.id}}: listener for event ${type} has already been added to this entity {${this}}. This is usually not intended.`
1226
+ );
1227
+ }
1219
1228
  this.eventListeners.push(eventListener);
1220
1229
  }
1221
1230
  parseLayoutConstraints(constraints, allGameEntities) {
@@ -1794,6 +1803,7 @@ Constants.FREE_ENTITIES_SCENE_NAME = "__freeEntitiesScene";
1794
1803
  Constants.OUTGOING_SCENE_NAME = "__outgoingScene";
1795
1804
  Constants.OUTGOING_SCENE_SPRITE_NAME = "__outgoingSceneSprite";
1796
1805
  Constants.OUTGOING_SCENE_IMAGE_NAME = "__outgoingSceneSnapshot";
1806
+ Constants.SESSION_INITIALIZATION_POLLING_INTERVAL_MS = 50;
1797
1807
 
1798
1808
  var Dimensions = /* @__PURE__ */ ((Dimensions2) => {
1799
1809
  Dimensions2[Dimensions2["MatchConstraint"] = 0] = "MatchConstraint";
@@ -2097,7 +2107,13 @@ class FontManager {
2097
2107
  return Promise.all([Promise.resolve()]);
2098
2108
  }
2099
2109
  const fetchFontsPromises = fontsToFetch.map((font) => {
2110
+ if (!font) {
2111
+ throw new Error("font undefined");
2112
+ }
2100
2113
  const game = games.filter((g) => g.uuid === font.gameUuid).find(Boolean);
2114
+ if (!game) {
2115
+ throw new Error("game undefined");
2116
+ }
2101
2117
  const fontUrl = game.prependAssetsGameIdUrl(font.fontUrl);
2102
2118
  return fetch(fontUrl).then((response) => response.arrayBuffer()).then((arrayBuffer) => {
2103
2119
  this.fontData.push({
@@ -2170,21 +2186,21 @@ class FontManager {
2170
2186
  }
2171
2187
  }
2172
2188
 
2173
- var __defProp$6 = Object.defineProperty;
2189
+ var __defProp$7 = Object.defineProperty;
2174
2190
  var __defProps$5 = Object.defineProperties;
2175
2191
  var __getOwnPropDescs$5 = Object.getOwnPropertyDescriptors;
2176
- var __getOwnPropSymbols$6 = Object.getOwnPropertySymbols;
2177
- var __hasOwnProp$6 = Object.prototype.hasOwnProperty;
2178
- var __propIsEnum$6 = Object.prototype.propertyIsEnumerable;
2179
- var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2180
- var __spreadValues$6 = (a, b) => {
2192
+ var __getOwnPropSymbols$7 = Object.getOwnPropertySymbols;
2193
+ var __hasOwnProp$7 = Object.prototype.hasOwnProperty;
2194
+ var __propIsEnum$7 = Object.prototype.propertyIsEnumerable;
2195
+ var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2196
+ var __spreadValues$7 = (a, b) => {
2181
2197
  for (var prop in b || (b = {}))
2182
- if (__hasOwnProp$6.call(b, prop))
2183
- __defNormalProp$6(a, prop, b[prop]);
2184
- if (__getOwnPropSymbols$6)
2185
- for (var prop of __getOwnPropSymbols$6(b)) {
2186
- if (__propIsEnum$6.call(b, prop))
2187
- __defNormalProp$6(a, prop, b[prop]);
2198
+ if (__hasOwnProp$7.call(b, prop))
2199
+ __defNormalProp$7(a, prop, b[prop]);
2200
+ if (__getOwnPropSymbols$7)
2201
+ for (var prop of __getOwnPropSymbols$7(b)) {
2202
+ if (__propIsEnum$7.call(b, prop))
2203
+ __defNormalProp$7(a, prop, b[prop]);
2188
2204
  }
2189
2205
  return a;
2190
2206
  };
@@ -2193,7 +2209,7 @@ class Sprite extends Entity {
2193
2209
  /**
2194
2210
  * Visual image displayed on the screen.
2195
2211
  *
2196
- * @remarks Images that will be used to create the sprite must be loaded during the Game.init() method prior to their use.
2212
+ * @remarks Images that will be used to create the sprite must be loaded during the Game.initialize() method prior to their use.
2197
2213
  *
2198
2214
  * @param options - {@link SpriteOptions}
2199
2215
  */
@@ -2250,7 +2266,7 @@ class Sprite extends Entity {
2250
2266
  * provided, name will be the new uuid
2251
2267
  */
2252
2268
  duplicate(newName) {
2253
- const dest = new Sprite(__spreadProps$5(__spreadValues$6(__spreadValues$6({}, this.getEntityOptions()), this.getDrawableOptions()), {
2269
+ const dest = new Sprite(__spreadProps$5(__spreadValues$7(__spreadValues$7({}, this.getEntityOptions()), this.getDrawableOptions()), {
2254
2270
  imageName: this.imageName,
2255
2271
  name: newName
2256
2272
  }));
@@ -2305,21 +2321,21 @@ class LoadedImage {
2305
2321
  }
2306
2322
  }
2307
2323
 
2308
- var __defProp$5 = Object.defineProperty;
2324
+ var __defProp$6 = Object.defineProperty;
2309
2325
  var __defProps$4 = Object.defineProperties;
2310
2326
  var __getOwnPropDescs$4 = Object.getOwnPropertyDescriptors;
2311
- var __getOwnPropSymbols$5 = Object.getOwnPropertySymbols;
2312
- var __hasOwnProp$5 = Object.prototype.hasOwnProperty;
2313
- var __propIsEnum$5 = Object.prototype.propertyIsEnumerable;
2314
- var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2315
- var __spreadValues$5 = (a, b) => {
2327
+ var __getOwnPropSymbols$6 = Object.getOwnPropertySymbols;
2328
+ var __hasOwnProp$6 = Object.prototype.hasOwnProperty;
2329
+ var __propIsEnum$6 = Object.prototype.propertyIsEnumerable;
2330
+ var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2331
+ var __spreadValues$6 = (a, b) => {
2316
2332
  for (var prop in b || (b = {}))
2317
- if (__hasOwnProp$5.call(b, prop))
2318
- __defNormalProp$5(a, prop, b[prop]);
2319
- if (__getOwnPropSymbols$5)
2320
- for (var prop of __getOwnPropSymbols$5(b)) {
2321
- if (__propIsEnum$5.call(b, prop))
2322
- __defNormalProp$5(a, prop, b[prop]);
2333
+ if (__hasOwnProp$6.call(b, prop))
2334
+ __defNormalProp$6(a, prop, b[prop]);
2335
+ if (__getOwnPropSymbols$6)
2336
+ for (var prop of __getOwnPropSymbols$6(b)) {
2337
+ if (__propIsEnum$6.call(b, prop))
2338
+ __defNormalProp$6(a, prop, b[prop]);
2323
2339
  }
2324
2340
  return a;
2325
2341
  };
@@ -2399,7 +2415,7 @@ class Scene extends Entity {
2399
2415
  * provided, name will be the new uuid
2400
2416
  */
2401
2417
  duplicate(newName) {
2402
- const dest = new Scene(__spreadProps$4(__spreadValues$5(__spreadValues$5({}, this.getEntityOptions()), this.getDrawableOptions()), {
2418
+ const dest = new Scene(__spreadProps$4(__spreadValues$6(__spreadValues$6({}, this.getEntityOptions()), this.getDrawableOptions()), {
2403
2419
  backgroundColor: this.backgroundColor,
2404
2420
  name: newName
2405
2421
  }));
@@ -2814,19 +2830,19 @@ class WebGlInfo {
2814
2830
  }
2815
2831
  }
2816
2832
 
2817
- var __defProp$4 = Object.defineProperty;
2818
- var __getOwnPropSymbols$4 = Object.getOwnPropertySymbols;
2819
- var __hasOwnProp$4 = Object.prototype.hasOwnProperty;
2820
- var __propIsEnum$4 = Object.prototype.propertyIsEnumerable;
2821
- var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2822
- var __spreadValues$4 = (a, b) => {
2833
+ var __defProp$5 = Object.defineProperty;
2834
+ var __getOwnPropSymbols$5 = Object.getOwnPropertySymbols;
2835
+ var __hasOwnProp$5 = Object.prototype.hasOwnProperty;
2836
+ var __propIsEnum$5 = Object.prototype.propertyIsEnumerable;
2837
+ var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
2838
+ var __spreadValues$5 = (a, b) => {
2823
2839
  for (var prop in b || (b = {}))
2824
- if (__hasOwnProp$4.call(b, prop))
2825
- __defNormalProp$4(a, prop, b[prop]);
2826
- if (__getOwnPropSymbols$4)
2827
- for (var prop of __getOwnPropSymbols$4(b)) {
2828
- if (__propIsEnum$4.call(b, prop))
2829
- __defNormalProp$4(a, prop, b[prop]);
2840
+ if (__hasOwnProp$5.call(b, prop))
2841
+ __defNormalProp$5(a, prop, b[prop]);
2842
+ if (__getOwnPropSymbols$5)
2843
+ for (var prop of __getOwnPropSymbols$5(b)) {
2844
+ if (__propIsEnum$5.call(b, prop))
2845
+ __defNormalProp$5(a, prop, b[prop]);
2830
2846
  }
2831
2847
  return a;
2832
2848
  };
@@ -2922,7 +2938,7 @@ class I18n {
2922
2938
  const processedLocales = new Array();
2923
2939
  for (const locale in baseTranslations) {
2924
2940
  processedLocales.push(locale);
2925
- result[locale] = __spreadValues$4(__spreadValues$4({}, baseTranslations[locale]), additionalTranslations[locale]);
2941
+ result[locale] = __spreadValues$5(__spreadValues$5({}, baseTranslations[locale]), additionalTranslations[locale]);
2926
2942
  }
2927
2943
  for (const locale in additionalTranslations) {
2928
2944
  if (processedLocales.includes(locale)) {
@@ -3052,21 +3068,21 @@ var ShapeType = /* @__PURE__ */ ((ShapeType2) => {
3052
3068
  return ShapeType2;
3053
3069
  })(ShapeType || {});
3054
3070
 
3055
- var __defProp$3 = Object.defineProperty;
3071
+ var __defProp$4 = Object.defineProperty;
3056
3072
  var __defProps$3 = Object.defineProperties;
3057
3073
  var __getOwnPropDescs$3 = Object.getOwnPropertyDescriptors;
3058
- var __getOwnPropSymbols$3 = Object.getOwnPropertySymbols;
3059
- var __hasOwnProp$3 = Object.prototype.hasOwnProperty;
3060
- var __propIsEnum$3 = Object.prototype.propertyIsEnumerable;
3061
- var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3062
- var __spreadValues$3 = (a, b) => {
3074
+ var __getOwnPropSymbols$4 = Object.getOwnPropertySymbols;
3075
+ var __hasOwnProp$4 = Object.prototype.hasOwnProperty;
3076
+ var __propIsEnum$4 = Object.prototype.propertyIsEnumerable;
3077
+ var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3078
+ var __spreadValues$4 = (a, b) => {
3063
3079
  for (var prop in b || (b = {}))
3064
- if (__hasOwnProp$3.call(b, prop))
3065
- __defNormalProp$3(a, prop, b[prop]);
3066
- if (__getOwnPropSymbols$3)
3067
- for (var prop of __getOwnPropSymbols$3(b)) {
3068
- if (__propIsEnum$3.call(b, prop))
3069
- __defNormalProp$3(a, prop, b[prop]);
3080
+ if (__hasOwnProp$4.call(b, prop))
3081
+ __defNormalProp$4(a, prop, b[prop]);
3082
+ if (__getOwnPropSymbols$4)
3083
+ for (var prop of __getOwnPropSymbols$4(b)) {
3084
+ if (__propIsEnum$4.call(b, prop))
3085
+ __defNormalProp$4(a, prop, b[prop]);
3070
3086
  }
3071
3087
  return a;
3072
3088
  };
@@ -3074,11 +3090,11 @@ var __spreadProps$3 = (a, b) => __defProps$3(a, __getOwnPropDescs$3(b));
3074
3090
  var __objRest = (source, exclude) => {
3075
3091
  var target = {};
3076
3092
  for (var prop in source)
3077
- if (__hasOwnProp$3.call(source, prop) && exclude.indexOf(prop) < 0)
3093
+ if (__hasOwnProp$4.call(source, prop) && exclude.indexOf(prop) < 0)
3078
3094
  target[prop] = source[prop];
3079
- if (source != null && __getOwnPropSymbols$3)
3080
- for (var prop of __getOwnPropSymbols$3(source)) {
3081
- if (exclude.indexOf(prop) < 0 && __propIsEnum$3.call(source, prop))
3095
+ if (source != null && __getOwnPropSymbols$4)
3096
+ for (var prop of __getOwnPropSymbols$4(source)) {
3097
+ if (exclude.indexOf(prop) < 0 && __propIsEnum$4.call(source, prop))
3082
3098
  target[prop] = source[prop];
3083
3099
  }
3084
3100
  return target;
@@ -3094,6 +3110,7 @@ class Game {
3094
3110
  this.uuid = Uuid.generate();
3095
3111
  this.beginTimestamp = NaN;
3096
3112
  this.beginIso8601Timestamp = "";
3113
+ this.eventListeners = new Array();
3097
3114
  this.gameMetrics = new Array();
3098
3115
  this.stepCount = 0;
3099
3116
  this.steppingNow = 0;
@@ -3172,15 +3189,30 @@ class Game {
3172
3189
  this.fpsMetricReportThreshold = (_a = options.fpsMetricReportThreshold) != null ? _a : Constants.FPS_METRIC_REPORT_THRESHOLD;
3173
3190
  this.maximumRecordedActivityMetrics = (_b = options.maximumRecordedActivityMetrics) != null ? _b : Constants.MAXIMUM_RECORDED_ACTIVITY_METRICS;
3174
3191
  this.addLocalizationParametersToGameParameters();
3192
+ if (!this.options.trialSchema) {
3193
+ this.options.trialSchema = {};
3194
+ }
3175
3195
  }
3176
3196
  addLocalizationParametersToGameParameters() {
3177
- this.options.parameters = __spreadValues$3(__spreadValues$3({}, this.options.parameters), I18n.makeLocalizationParameters());
3197
+ this.options.parameters = __spreadValues$4(__spreadValues$4({}, this.options.parameters), I18n.makeLocalizationParameters());
3178
3198
  }
3179
3199
  async init() {
3200
+ return this.initialize();
3201
+ }
3202
+ async initialize() {
3203
+ var _a, _b;
3180
3204
  if (this.isLocalizationRequested()) {
3181
3205
  const options = this.getLocalizationOptionsFromGameParameters();
3182
3206
  this.i18n = new I18n(options);
3183
3207
  }
3208
+ if ((_a = this.session.options.activityCallbacks) == null ? void 0 : _a.onActivityLifecycle) {
3209
+ this.onStart(this.session.options.activityCallbacks.onActivityLifecycle);
3210
+ this.onCancel(this.session.options.activityCallbacks.onActivityLifecycle);
3211
+ this.onEnd(this.session.options.activityCallbacks.onActivityLifecycle);
3212
+ }
3213
+ if ((_b = this.session.options.activityCallbacks) == null ? void 0 : _b.onActivityResults) {
3214
+ this.onData(this.session.options.activityCallbacks.onActivityResults);
3215
+ }
3184
3216
  }
3185
3217
  /**
3186
3218
  * Saves an item to the activity's key-value store.
@@ -3190,7 +3222,7 @@ class Game {
3190
3222
  * ```
3191
3223
  * const db: IDataStore = new LocalDatabase();
3192
3224
  * session.dataStore = db;
3193
- * session.init();
3225
+ * session.initialize();
3194
3226
  * ```
3195
3227
  * @param key - item key
3196
3228
  * @param value - item value
@@ -3212,7 +3244,7 @@ class Game {
3212
3244
  * ```
3213
3245
  * const db: IDataStore = new LocalDatabase();
3214
3246
  * session.dataStore = db;
3215
- * session.init();
3247
+ * session.initialize();
3216
3248
  * ```
3217
3249
  * @param key - item key
3218
3250
  * @param globalStore - if true, treat the item as "global" and not
@@ -3232,7 +3264,7 @@ class Game {
3232
3264
  * ```
3233
3265
  * const db: IDataStore = new LocalDatabase();
3234
3266
  * session.dataStore = db;
3235
- * session.init();
3267
+ * session.initialize();
3236
3268
  * ```
3237
3269
  * @param key - item key
3238
3270
  * @param globalStore - if true, treat the item as "global" and not
@@ -3251,7 +3283,7 @@ class Game {
3251
3283
  * ```
3252
3284
  * const db: IDataStore = new LocalDatabase();
3253
3285
  * session.dataStore = db;
3254
- * session.init();
3286
+ * session.initialize();
3255
3287
  * ```
3256
3288
  */
3257
3289
  storeClearItems() {
@@ -3265,7 +3297,7 @@ class Game {
3265
3297
  * ```
3266
3298
  * const db: IDataStore = new LocalDatabase();
3267
3299
  * session.dataStore = db;
3268
- * session.init();
3300
+ * session.initialize();
3269
3301
  * ```
3270
3302
  * @param globalStore - if true, treat the item as "global" and not
3271
3303
  * associated with a specific activity; global items can be accessed
@@ -3282,7 +3314,7 @@ class Game {
3282
3314
  * ```
3283
3315
  * const db: IDataStore = new LocalDatabase();
3284
3316
  * session.dataStore = db;
3285
- * session.init();
3317
+ * session.initialize();
3286
3318
  * ```
3287
3319
  * @param key - item key
3288
3320
  * @param globalStore - if true, treat the item as "global" and not
@@ -3561,7 +3593,7 @@ class Game {
3561
3593
  * @param entryScene - The scene (Scene object or its string name) to display when the game starts
3562
3594
  */
3563
3595
  async start(entryScene) {
3564
- var _a, _b, _c;
3596
+ var _a, _b;
3565
3597
  const gameInitOptions = this.options;
3566
3598
  this.unitTesting = (_a = gameInitOptions._unitTesting) != null ? _a : false;
3567
3599
  this.setupHtmlCanvases(
@@ -3621,12 +3653,11 @@ class Game {
3621
3653
  warmupFunction: this.warmupShadersWithScenes
3622
3654
  });
3623
3655
  this.surface.requestAnimationFrame(this.loop.bind(this));
3624
- if ((_c = this.session.options.activityCallbacks) == null ? void 0 : _c.onActivityLifecycle) {
3625
- this.session.options.activityCallbacks.onActivityLifecycle({
3626
- type: EventType.ActivityStart,
3627
- target: this
3628
- });
3629
- }
3656
+ const activityStartEvent = {
3657
+ target: this,
3658
+ type: EventType.ActivityStart
3659
+ };
3660
+ this.raiseActivityEventOnListeners(activityStartEvent);
3630
3661
  }
3631
3662
  addTimeSteppingControlsToDom() {
3632
3663
  const existingDiv = document.getElementById("m2c2kit-time-stepping-div");
@@ -3956,7 +3987,7 @@ class Game {
3956
3987
  for (const [variableName2] of variables) {
3957
3988
  emptyTrial[variableName2] = null;
3958
3989
  }
3959
- this.data.trials.push(__spreadProps$3(__spreadValues$3({
3990
+ this.data.trials.push(__spreadProps$3(__spreadValues$4({
3960
3991
  document_uuid: Uuid.generate(),
3961
3992
  session_uuid: this.session.uuid,
3962
3993
  activity_uuid: this.uuid,
@@ -4008,6 +4039,9 @@ class Game {
4008
4039
  addTrialSchema(schema) {
4009
4040
  const keys = Object.keys(schema);
4010
4041
  keys.forEach((key) => {
4042
+ if (!this.options.trialSchema) {
4043
+ throw new Error("trial schema is undefined");
4044
+ }
4011
4045
  this.options.trialSchema[key] = schema[key];
4012
4046
  });
4013
4047
  }
@@ -4037,6 +4071,9 @@ class Game {
4037
4071
  * @param value - value of the variable to set
4038
4072
  */
4039
4073
  addStaticTrialData(variableName, value) {
4074
+ if (!this.options.trialSchema) {
4075
+ throw new Error("trial schema is undefined");
4076
+ }
4040
4077
  if (this.options.trialSchema[variableName] === void 0) {
4041
4078
  throw new Error(`trial variable ${variableName} not defined in schema`);
4042
4079
  }
@@ -4053,31 +4090,30 @@ class Game {
4053
4090
  * the appropriate time. It is not triggered automatically.
4054
4091
  */
4055
4092
  trialComplete() {
4056
- var _a, _b, _c;
4093
+ var _a, _b;
4057
4094
  if (Object.keys(this.staticTrialSchema).length > 0) {
4058
- this.data.trials[this.trialIndex] = __spreadValues$3(__spreadValues$3({}, this.data.trials[this.trialIndex]), this.staticTrialSchema);
4095
+ this.data.trials[this.trialIndex] = __spreadValues$4(__spreadValues$4({}, this.data.trials[this.trialIndex]), this.staticTrialSchema);
4059
4096
  }
4060
4097
  this.trialIndex++;
4061
- if ((_a = this.session.options.activityCallbacks) == null ? void 0 : _a.onActivityResults) {
4062
- this.session.options.activityCallbacks.onActivityResults({
4063
- type: EventType.ActivityData,
4064
- iso8601Timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4065
- target: this,
4066
- /** newData is only the trial that recently completed */
4067
- newData: this.data.trials[this.trialIndex - 1],
4068
- newDataSchema: this.makeNewGameDataSchema(),
4069
- /** data is all the data collected so far in the game */
4070
- data: this.data,
4071
- dataSchema: this.makeGameDataSchema(),
4072
- activityConfiguration: this.makeGameActivityConfiguration(
4073
- (_b = this.options.parameters) != null ? _b : {}
4074
- ),
4075
- activityConfigurationSchema: this.makeGameActivityConfigurationSchema(
4076
- (_c = this.options.parameters) != null ? _c : {}
4077
- ),
4078
- activityMetrics: this.gameMetrics
4079
- });
4080
- }
4098
+ const resultsEvent = {
4099
+ type: EventType.ActivityData,
4100
+ iso8601Timestamp: (/* @__PURE__ */ new Date()).toISOString(),
4101
+ target: this,
4102
+ /** newData is only the trial that recently completed */
4103
+ newData: this.data.trials[this.trialIndex - 1],
4104
+ newDataSchema: this.makeNewGameDataSchema(),
4105
+ /** data is all the data collected so far in the game */
4106
+ data: this.data,
4107
+ dataSchema: this.makeGameDataSchema(),
4108
+ activityConfiguration: this.makeGameActivityConfiguration(
4109
+ (_a = this.options.parameters) != null ? _a : {}
4110
+ ),
4111
+ activityConfigurationSchema: this.makeGameActivityConfigurationSchema(
4112
+ (_b = this.options.parameters) != null ? _b : {}
4113
+ ),
4114
+ activityMetrics: this.gameMetrics
4115
+ };
4116
+ this.raiseActivityEventOnListeners(resultsEvent);
4081
4117
  }
4082
4118
  makeNewGameDataSchema() {
4083
4119
  const newDataSchema = {
@@ -4085,7 +4121,7 @@ class Game {
4085
4121
  $comment: `Activity identifier: ${this.options.id}, version: ${this.options.version}.`,
4086
4122
  $schema: "https://json-schema.org/draft/2019-09/schema",
4087
4123
  type: "object",
4088
- properties: __spreadProps$3(__spreadValues$3(__spreadValues$3({}, this.automaticTrialSchema), this.options.trialSchema), {
4124
+ properties: __spreadProps$3(__spreadValues$4(__spreadValues$4({}, this.automaticTrialSchema), this.options.trialSchema), {
4089
4125
  device_metadata: deviceMetadataSchema
4090
4126
  })
4091
4127
  };
@@ -4108,7 +4144,7 @@ class Game {
4108
4144
  $defs: {
4109
4145
  trial: {
4110
4146
  type: "object",
4111
- properties: __spreadProps$3(__spreadValues$3(__spreadValues$3({}, this.automaticTrialSchema), this.options.trialSchema), {
4147
+ properties: __spreadProps$3(__spreadValues$4(__spreadValues$4({}, this.automaticTrialSchema), this.options.trialSchema), {
4112
4148
  device_metadata: deviceMetadataSchema
4113
4149
  })
4114
4150
  }
@@ -4176,60 +4212,60 @@ class Game {
4176
4212
  /**
4177
4213
  * Should be called when current game has ended successfully.
4178
4214
  *
4179
- * @remarks This will trigger the onActivityLifecycleChange callback function,
4180
- * if one was provided in SessionOptions. This is how the game can communicate
4181
- * its state to the parent session. It is the responsibility of the the game
4182
- * programmer to call this at the appropriate time. It is not triggered
4183
- * automatically.
4215
+ * @remarks This will send an ActivityEnd event to any listeners, such as
4216
+ * a function provided to Game.onEnd() or a callback defined in
4217
+ * SessionOptions.activityCallbacks.onActivityLifecycle. This is how the
4218
+ * game can communicate changes in activity state to the parent session.
4219
+ * It is the responsibility of the the game programmer to call this at the
4220
+ * appropriate time. It is not triggered automatically.
4184
4221
  */
4185
4222
  end() {
4186
- var _a, _b, _c;
4187
- if ((_a = this.session.options.activityCallbacks) == null ? void 0 : _a.onActivityLifecycle) {
4188
- this.session.options.activityCallbacks.onActivityLifecycle({
4189
- type: EventType.ActivityEnd,
4190
- target: this,
4191
- results: {
4192
- data: this.data,
4193
- dataSchema: this.makeGameDataSchema(),
4194
- activityConfiguration: this.makeGameActivityConfiguration(
4195
- (_b = this.options.parameters) != null ? _b : {}
4196
- ),
4197
- activityConfigurationSchema: this.makeGameActivityConfigurationSchema(
4198
- (_c = this.options.parameters) != null ? _c : {}
4199
- ),
4200
- activityMetrics: this.gameMetrics
4201
- }
4202
- });
4203
- }
4223
+ var _a, _b;
4224
+ const activityEndEvent = {
4225
+ target: this,
4226
+ type: EventType.ActivityEnd
4227
+ };
4228
+ const results = {
4229
+ data: this.data,
4230
+ dataSchema: this.makeGameDataSchema(),
4231
+ activityConfiguration: this.makeGameActivityConfiguration(
4232
+ (_a = this.options.parameters) != null ? _a : {}
4233
+ ),
4234
+ activityConfigurationSchema: this.makeGameActivityConfigurationSchema(
4235
+ (_b = this.options.parameters) != null ? _b : {}
4236
+ ),
4237
+ activityMetrics: this.gameMetrics
4238
+ };
4239
+ this.raiseActivityEventOnListeners(activityEndEvent, results);
4204
4240
  }
4205
4241
  /**
4206
4242
  * Should be called when current game has been canceled by a user action.
4207
4243
  *
4208
- * @remarks This will trigger the onActivityLifecycleChange callback function,
4209
- * if one was provided in SessionOptions. This is how the game can communicate
4210
- * its state to the parent session. It is the responsibility of the the game
4211
- * programmer to call this at the appropriate time. It is not triggered
4212
- * automatically.
4244
+ * @remarks This will send an ActivityCancel event to any listeners, such as
4245
+ * a function provided to Game.onCancel() or a callback defined in
4246
+ * SessionOptions.activityCallbacks.onActivityLifecycle. This is how the
4247
+ * game can communicate changes in activity state to the parent session.
4248
+ * It is the responsibility of the the game programmer to call this at the
4249
+ * appropriate time. It is not triggered automatically.
4213
4250
  */
4214
4251
  cancel() {
4215
- var _a, _b, _c;
4216
- if ((_a = this.session.options.activityCallbacks) == null ? void 0 : _a.onActivityLifecycle) {
4217
- this.session.options.activityCallbacks.onActivityLifecycle({
4218
- type: EventType.ActivityCancel,
4219
- target: this,
4220
- results: {
4221
- data: this.data,
4222
- dataSchema: this.makeGameDataSchema(),
4223
- activityConfiguration: this.makeGameActivityConfiguration(
4224
- (_b = this.options.parameters) != null ? _b : {}
4225
- ),
4226
- activityConfigurationSchema: this.makeGameActivityConfigurationSchema(
4227
- (_c = this.options.parameters) != null ? _c : {}
4228
- ),
4229
- activityMetrics: this.gameMetrics
4230
- }
4231
- });
4232
- }
4252
+ var _a, _b;
4253
+ const activityCancelEvent = {
4254
+ target: this,
4255
+ type: EventType.ActivityCancel
4256
+ };
4257
+ const results = {
4258
+ data: this.data,
4259
+ dataSchema: this.makeGameDataSchema(),
4260
+ activityConfiguration: this.makeGameActivityConfiguration(
4261
+ (_a = this.options.parameters) != null ? _a : {}
4262
+ ),
4263
+ activityConfigurationSchema: this.makeGameActivityConfigurationSchema(
4264
+ (_b = this.options.parameters) != null ? _b : {}
4265
+ ),
4266
+ activityMetrics: this.gameMetrics
4267
+ };
4268
+ this.raiseActivityEventOnListeners(activityCancelEvent, results);
4233
4269
  }
4234
4270
  setupHtmlCanvases(canvasId, width, height, stretch) {
4235
4271
  Globals.canvasScale = Math.round(window.devicePixelRatio * 100) / 100;
@@ -4830,10 +4866,10 @@ class Game {
4830
4866
  *
4831
4867
  * @param type - the type of event to listen for, e.g., "tapDown"
4832
4868
  * @param entityName - the entity name for which an event will be listened
4833
- * @param callback
4834
- * @param replaceExistingCallback
4869
+ * @param callback - the callback to be invoked when the event occurs
4870
+ * @param callbackOptions
4835
4871
  */
4836
- createEventListener(type, entityName, callback, replaceExistingCallback = true) {
4872
+ createEventListener(type, entityName, callback, callbackOptions) {
4837
4873
  const entities = this.entities.filter(
4838
4874
  (entity2) => entity2.name === entityName
4839
4875
  );
@@ -4848,17 +4884,12 @@ class Game {
4848
4884
  `could not create event listener. entity with name ${entityName} could not be found in the game entity tree`
4849
4885
  );
4850
4886
  }
4851
- switch (type) {
4852
- case EventType.PointerDown: {
4853
- entity.onPointerDown(callback, replaceExistingCallback);
4854
- break;
4855
- }
4856
- default: {
4857
- throw new Error(
4858
- `could not create event listener: event type ${type} is not known`
4859
- );
4860
- }
4887
+ if (!Object.values(EventType).includes(type)) {
4888
+ throw new Error(
4889
+ `game ${this.id}: could not create event listener. event type ${type} is not known`
4890
+ );
4861
4891
  }
4892
+ entity.addEventListener(type, callback, callbackOptions);
4862
4893
  }
4863
4894
  /**
4864
4895
  * Returns array of all entities that have been added to the game object.
@@ -5196,6 +5227,67 @@ class Game {
5196
5227
  const relativeY = (y - bb.yMin) / (bb.yMax - bb.yMin) * height;
5197
5228
  return { x: relativeX, y: relativeY };
5198
5229
  }
5230
+ /**
5231
+ * Executes a callback when the game starts.
5232
+ *
5233
+ * @param callback - function to execute.
5234
+ * @param options - options for the callback.
5235
+ */
5236
+ onStart(callback, options) {
5237
+ this.addEventListener(EventType.ActivityStart, callback, options);
5238
+ }
5239
+ /**
5240
+ * Executes a callback when the game is canceled.
5241
+ *
5242
+ * @param callback - function to execute.
5243
+ * @param options - options for the callback.
5244
+ */
5245
+ onCancel(callback, options) {
5246
+ this.addEventListener(EventType.ActivityCancel, callback, options);
5247
+ }
5248
+ /**
5249
+ * Executes a callback when the game ends.
5250
+ *
5251
+ * @param callback - function to execute.
5252
+ * @param options - options for the callback.
5253
+ */
5254
+ onEnd(callback, options) {
5255
+ this.addEventListener(EventType.ActivityEnd, callback, options);
5256
+ }
5257
+ /**
5258
+ * Executes a callback when the game generates data.
5259
+ *
5260
+ * @param callback - function to execute.
5261
+ * @param options - options for the callback.
5262
+ */
5263
+ onData(callback, options) {
5264
+ this.addEventListener(
5265
+ EventType.ActivityData,
5266
+ callback,
5267
+ options
5268
+ );
5269
+ }
5270
+ addEventListener(type, callback, options) {
5271
+ const eventListener = {
5272
+ type,
5273
+ activityUuid: this.uuid,
5274
+ callback
5275
+ };
5276
+ if (options == null ? void 0 : options.replaceExisting) {
5277
+ this.eventListeners = this.eventListeners.filter(
5278
+ (listener) => !(listener.activityUuid === eventListener.activityUuid && listener.type === eventListener.type)
5279
+ );
5280
+ }
5281
+ this.eventListeners.push(eventListener);
5282
+ }
5283
+ raiseActivityEventOnListeners(activityEvent, extra) {
5284
+ if (extra) {
5285
+ activityEvent = __spreadValues$4(__spreadValues$4({}, activityEvent), extra);
5286
+ }
5287
+ this.eventListeners.filter((listener) => listener.type === activityEvent.type).forEach((listener) => {
5288
+ listener.callback(activityEvent);
5289
+ });
5290
+ }
5199
5291
  raiseEventOnListeningEntities(entity, m2Event, domEvent) {
5200
5292
  entity.eventListeners.filter((listener) => listener.type === m2Event.type).forEach((listener) => {
5201
5293
  if (listener.entityUuid === entity.uuid) {
@@ -5535,6 +5627,9 @@ class ImageManager {
5535
5627
  reloadImageUsingViewBoxWidthHeight(svgElement);
5536
5628
  } else if (browserImage.url) {
5537
5629
  const game = this.session.options.activities.filter((a) => a.type === ActivityType.Game).filter((g) => g.uuid === gameUuid).map((g) => g).find(Boolean);
5630
+ if (!game) {
5631
+ throw new Error("game undefined");
5632
+ }
5538
5633
  const browserImageUrl = game.prependAssetsGameIdUrl(
5539
5634
  browserImage.url
5540
5635
  );
@@ -5575,6 +5670,9 @@ class ImageManager {
5575
5670
  image.src = "data:image/svg+xml," + encodeURIComponent(browserImage.svgString);
5576
5671
  } else if (browserImage.url) {
5577
5672
  const game = this.session.options.activities.filter((a) => a.type === ActivityType.Game).filter((g) => g.uuid === gameUuid).map((g) => g).find(Boolean);
5673
+ if (!game) {
5674
+ throw new Error("game undefined");
5675
+ }
5578
5676
  const browserImageUrl = game.prependAssetsGameIdUrl(browserImage.url);
5579
5677
  fetch(browserImageUrl).then((response) => response.arrayBuffer()).then((data) => {
5580
5678
  const base64String = this.arrayBufferToBase64String(data);
@@ -5684,21 +5782,21 @@ var LabelHorizontalAlignmentMode = /* @__PURE__ */ ((LabelHorizontalAlignmentMod
5684
5782
  return LabelHorizontalAlignmentMode2;
5685
5783
  })(LabelHorizontalAlignmentMode || {});
5686
5784
 
5687
- var __defProp$2 = Object.defineProperty;
5785
+ var __defProp$3 = Object.defineProperty;
5688
5786
  var __defProps$2 = Object.defineProperties;
5689
5787
  var __getOwnPropDescs$2 = Object.getOwnPropertyDescriptors;
5690
- var __getOwnPropSymbols$2 = Object.getOwnPropertySymbols;
5691
- var __hasOwnProp$2 = Object.prototype.hasOwnProperty;
5692
- var __propIsEnum$2 = Object.prototype.propertyIsEnumerable;
5693
- var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
5694
- var __spreadValues$2 = (a, b) => {
5788
+ var __getOwnPropSymbols$3 = Object.getOwnPropertySymbols;
5789
+ var __hasOwnProp$3 = Object.prototype.hasOwnProperty;
5790
+ var __propIsEnum$3 = Object.prototype.propertyIsEnumerable;
5791
+ var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
5792
+ var __spreadValues$3 = (a, b) => {
5695
5793
  for (var prop in b || (b = {}))
5696
- if (__hasOwnProp$2.call(b, prop))
5697
- __defNormalProp$2(a, prop, b[prop]);
5698
- if (__getOwnPropSymbols$2)
5699
- for (var prop of __getOwnPropSymbols$2(b)) {
5700
- if (__propIsEnum$2.call(b, prop))
5701
- __defNormalProp$2(a, prop, b[prop]);
5794
+ if (__hasOwnProp$3.call(b, prop))
5795
+ __defNormalProp$3(a, prop, b[prop]);
5796
+ if (__getOwnPropSymbols$3)
5797
+ for (var prop of __getOwnPropSymbols$3(b)) {
5798
+ if (__propIsEnum$3.call(b, prop))
5799
+ __defNormalProp$3(a, prop, b[prop]);
5702
5800
  }
5703
5801
  return a;
5704
5802
  };
@@ -5826,9 +5924,14 @@ class Label extends Entity {
5826
5924
  fontManager.gameTypefaces[this.game.uuid][this.fontName].fontFamily
5827
5925
  );
5828
5926
  } else {
5829
- fontFamilies.push(
5830
- Object.values(fontManager.gameTypefaces[this.game.uuid]).filter((f) => f.isDefault).find(Boolean).fontFamily
5927
+ const typefaces = Object.values(
5928
+ fontManager.gameTypefaces[this.game.uuid]
5831
5929
  );
5930
+ const defaultTypeface = typefaces.filter((f) => f.isDefault).find(Boolean);
5931
+ if (!defaultTypeface) {
5932
+ throw new Error("no default font");
5933
+ }
5934
+ fontFamilies.push(defaultTypeface.fontFamily);
5832
5935
  }
5833
5936
  this.paraStyle = new this.canvasKit.ParagraphStyle({
5834
5937
  textStyle: {
@@ -5948,7 +6051,7 @@ class Label extends Entity {
5948
6051
  * provided, name will be the new uuid
5949
6052
  */
5950
6053
  duplicate(newName) {
5951
- const dest = new Label(__spreadProps$2(__spreadValues$2(__spreadValues$2(__spreadValues$2({}, this.getEntityOptions()), this.getDrawableOptions()), this.getTextOptions()), {
6054
+ const dest = new Label(__spreadProps$2(__spreadValues$3(__spreadValues$3(__spreadValues$3({}, this.getEntityOptions()), this.getDrawableOptions()), this.getTextOptions()), {
5952
6055
  horizontalAlignmentMode: this.horizontalAlignmentMode,
5953
6056
  preferredMaxLayoutWidth: this.preferredMaxLayoutWidth,
5954
6057
  backgroundColor: this.backgroundColor,
@@ -6702,6 +6805,22 @@ var w;w||(w=typeof CanvasKitInit !== 'undefined' ? CanvasKitInit : {});var da,ea
6702
6805
  var canvaskitExports = canvaskit.exports;
6703
6806
  var CanvasKitInit = /*@__PURE__*/getDefaultExportFromCjs(canvaskitExports);
6704
6807
 
6808
+ var __defProp$2 = Object.defineProperty;
6809
+ var __getOwnPropSymbols$2 = Object.getOwnPropertySymbols;
6810
+ var __hasOwnProp$2 = Object.prototype.hasOwnProperty;
6811
+ var __propIsEnum$2 = Object.prototype.propertyIsEnumerable;
6812
+ var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6813
+ var __spreadValues$2 = (a, b) => {
6814
+ for (var prop in b || (b = {}))
6815
+ if (__hasOwnProp$2.call(b, prop))
6816
+ __defNormalProp$2(a, prop, b[prop]);
6817
+ if (__getOwnPropSymbols$2)
6818
+ for (var prop of __getOwnPropSymbols$2(b)) {
6819
+ if (__propIsEnum$2.call(b, prop))
6820
+ __defNormalProp$2(a, prop, b[prop]);
6821
+ }
6822
+ return a;
6823
+ };
6705
6824
  class Session {
6706
6825
  /**
6707
6826
  * A Session contains one or more activities. The session manages the start
@@ -6710,8 +6829,10 @@ class Session {
6710
6829
  * @param options
6711
6830
  */
6712
6831
  constructor(options) {
6832
+ this.eventListeners = new Array();
6713
6833
  this.sessionDictionary = /* @__PURE__ */ new Map();
6714
- this.version = "0.3.7 (402d543e)";
6834
+ this.initialized = false;
6835
+ this.version = "0.3.9 (ae8a7530)";
6715
6836
  this.options = options;
6716
6837
  for (const activity of this.options.activities) {
6717
6838
  if (this.options.activities.filter((a) => a === activity).length > 1) {
@@ -6729,61 +6850,253 @@ class Session {
6729
6850
  this.uuid = Uuid.generate();
6730
6851
  }
6731
6852
  }
6853
+ /**
6854
+ * Executes a callback when the session initializes.
6855
+ *
6856
+ * @param callback - function to execute.
6857
+ * @param options - options for the callback.
6858
+ */
6859
+ onInitialize(callback, options) {
6860
+ this.addEventListener(
6861
+ EventType.SessionInitialize,
6862
+ callback,
6863
+ options
6864
+ );
6865
+ }
6866
+ /**
6867
+ * Executes a callback when the session starts.
6868
+ *
6869
+ * @param callback - function to execute.
6870
+ * @param options - options for the callback.
6871
+ */
6872
+ onStart(callback, options) {
6873
+ this.addEventListener(
6874
+ EventType.SessionStart,
6875
+ callback,
6876
+ options
6877
+ );
6878
+ }
6879
+ /**
6880
+ * Executes a callback when the session ends.
6881
+ *
6882
+ * @param callback - function to execute.
6883
+ * @param options - options for the callback.
6884
+ */
6885
+ onEnd(callback, options) {
6886
+ this.addEventListener(
6887
+ EventType.SessionEnd,
6888
+ callback,
6889
+ options
6890
+ );
6891
+ }
6892
+ /**
6893
+ * Executes a callback when any activity in the session generates data.
6894
+ *
6895
+ * @param callback - function to execute.
6896
+ * @param options - options for the callback.
6897
+ */
6898
+ onActivityData(callback, options) {
6899
+ this.addEventListener(
6900
+ EventType.ActivityData,
6901
+ callback,
6902
+ options
6903
+ );
6904
+ }
6905
+ addEventListener(type, callback, options) {
6906
+ const eventListener = {
6907
+ type,
6908
+ callback,
6909
+ key: options == null ? void 0 : options.key
6910
+ };
6911
+ if (options == null ? void 0 : options.replaceExisting) {
6912
+ this.eventListeners = this.eventListeners.filter(
6913
+ (listener) => !(listener.type === eventListener.type)
6914
+ );
6915
+ }
6916
+ this.eventListeners.push(eventListener);
6917
+ }
6918
+ raiseEventOnListeners(event, extra) {
6919
+ if (extra) {
6920
+ event = __spreadValues$2(__spreadValues$2({}, event), extra);
6921
+ }
6922
+ this.eventListeners.filter((listener) => listener.type === event.type).forEach((listener) => {
6923
+ listener.callback(event);
6924
+ });
6925
+ }
6926
+ async sessionActivityStartHandler(event) {
6927
+ const activityType = event.target.type === ActivityType.Game ? "game" : "survey";
6928
+ console.log(`\u{1F7E2} started activity (${activityType}) ${event.target.name}`);
6929
+ }
6930
+ async sessionActivityCancelHandler(event) {
6931
+ const activityType = event.target.type === ActivityType.Game ? "game" : "survey";
6932
+ console.log(`\u{1F6AB} canceled activity (${activityType}) ${event.target.name}`);
6933
+ if (this.nextActivity && this.options.autoGoToNextActivity !== false) {
6934
+ await this.goToNextActivity();
6935
+ return;
6936
+ }
6937
+ if (!this.nextActivity && this.options.autoEndAfterLastActivity !== false) {
6938
+ this.end();
6939
+ }
6940
+ }
6941
+ async sessionActivityEndHandler(event) {
6942
+ const activityType = event.target.type === ActivityType.Game ? "game" : "survey";
6943
+ console.log(`\u{1F534} ended activity (${activityType}) ${event.target.name}`);
6944
+ if (this.nextActivity && this.options.autoGoToNextActivity !== false) {
6945
+ await this.goToNextActivity();
6946
+ return;
6947
+ }
6948
+ if (!this.nextActivity && this.options.autoEndAfterLastActivity !== false) {
6949
+ this.end();
6950
+ }
6951
+ }
6952
+ async sessionActivityLifecycleHandler(event) {
6953
+ if (event.type === EventType.ActivityStart) {
6954
+ await this.sessionActivityStartHandler(event);
6955
+ return;
6956
+ }
6957
+ if (event.type === EventType.ActivityCancel) {
6958
+ await this.sessionActivityCancelHandler(event);
6959
+ return;
6960
+ }
6961
+ if (event.type === EventType.ActivityEnd) {
6962
+ await this.sessionActivityEndHandler(event);
6963
+ return;
6964
+ }
6965
+ throw new Error("unknown activity lifecycle event type");
6966
+ }
6967
+ activityResultsEventHandler(event) {
6968
+ this.raiseEventOnListeners(event);
6969
+ }
6732
6970
  /**
6733
6971
  * Asynchronously initializes the m2c2kit engine and loads assets
6972
+ *
6973
+ * @deprecated Use Session.initialize() instead.
6734
6974
  */
6735
6975
  async init() {
6736
- var _a;
6976
+ console.warn(
6977
+ `The init() method of Session is deprecated. Use initialize() instead.`
6978
+ );
6979
+ return this.initialize();
6980
+ }
6981
+ /**
6982
+ * Check if the Activity uses the deprecated init() method.
6983
+ *
6984
+ * @remarks Activity.init() is deprecated and should be replaced with
6985
+ * Activity.initialize().
6986
+ *
6987
+ * @param activity
6988
+ * @returns true if the activity defines its own init() method, false otherwise.
6989
+ */
6990
+ activityUsesDeprecatedInit(activity) {
6991
+ if (activity.type === ActivityType.Survey) {
6992
+ return false;
6993
+ }
6994
+ const activityPrototype = Object.getPrototypeOf(activity);
6995
+ const gamePrototype = Object.getPrototypeOf(activityPrototype);
6996
+ return (activityPrototype == null ? void 0 : activityPrototype.init) !== (gamePrototype == null ? void 0 : gamePrototype.init);
6997
+ }
6998
+ /**
6999
+ * Asynchronously initializes the m2c2kit engine and loads assets
7000
+ */
7001
+ async initialize() {
6737
7002
  console.log(`\u26AA @m2c2kit/core version ${this.version}`);
6738
- Timer.start("sessionInit");
7003
+ Timer.start("sessionInitialize");
7004
+ const sessionInitializeEvent = {
7005
+ target: this,
7006
+ type: EventType.SessionInitialize
7007
+ };
7008
+ this.raiseEventOnListeners(sessionInitializeEvent);
6739
7009
  DomHelpers.addLoadingElements();
6740
7010
  DomHelpers.setSpinnerVisibility(true);
6741
7011
  DomHelpers.setCanvasOverlayVisibility(true);
6742
7012
  await Promise.all(
6743
7013
  this.options.activities.map((activity) => {
6744
7014
  activity.dataStore = this.dataStore;
6745
- return activity.init();
7015
+ activity.onStart(this.sessionActivityLifecycleHandler.bind(this));
7016
+ activity.onCancel(this.sessionActivityLifecycleHandler.bind(this));
7017
+ activity.onEnd(this.sessionActivityLifecycleHandler.bind(this));
7018
+ activity.onData((event) => {
7019
+ this.activityResultsEventHandler(event);
7020
+ });
7021
+ if (this.activityUsesDeprecatedInit(activity)) {
7022
+ console.warn(
7023
+ `game ${activity.id}: Activity.init() is deprecated. In the assessment class that extends Game, use Activity.initialize() instead:
7024
+ async initialize() {
7025
+ await super.initialize();
7026
+ ...
7027
+ }
7028
+ `
7029
+ );
7030
+ return activity.init();
7031
+ }
7032
+ return activity.initialize();
6746
7033
  })
6747
7034
  );
6748
7035
  const [canvasKit] = await this.getAsynchronousAssets();
6749
7036
  this.loadAssets(canvasKit);
6750
7037
  this.imageManager.removeScratchCanvas();
6751
7038
  console.log(
6752
- `\u26AA Session.init() took ${Timer.elapsed("sessionInit").toFixed(0)} ms`
7039
+ `\u26AA Session.sessionInitialize() took ${Timer.elapsed(
7040
+ "sessionInitialize"
7041
+ ).toFixed(0)} ms`
6753
7042
  );
6754
- Timer.remove("sessionInit");
6755
- const sessionLifecycleChangeCallback = (_a = this.options.sessionCallbacks) == null ? void 0 : _a.onSessionLifecycle;
6756
- if (sessionLifecycleChangeCallback) {
6757
- sessionLifecycleChangeCallback({
6758
- target: this,
6759
- type: EventType.SessionInitialize
6760
- });
7043
+ Timer.remove("sessionInitialize");
7044
+ this.initialized = true;
7045
+ if (this.options.autoStartAfterInit !== false) {
7046
+ await this.start();
7047
+ }
7048
+ }
7049
+ /**
7050
+ * Waits for the session to be initialized.
7051
+ *
7052
+ * @remarks Session.initialize() is asynchronous, and it should be awaited
7053
+ * so that the session is fully initialized before calling Session.start().
7054
+ * If it is not awaited (or it cannot be awaited because the target
7055
+ * environment does not support top-level await), this function ensures that
7056
+ * the session has been initialized.
7057
+ */
7058
+ async waitForSessionInitialization() {
7059
+ while (!this.initialized) {
7060
+ await new Promise(
7061
+ (resolve) => setTimeout(
7062
+ resolve,
7063
+ Constants.SESSION_INITIALIZATION_POLLING_INTERVAL_MS
7064
+ )
7065
+ );
6761
7066
  }
6762
7067
  }
6763
7068
  /**
6764
7069
  * Starts the session and starts the first activity.
6765
7070
  */
6766
7071
  async start() {
7072
+ await this.waitForSessionInitialization();
7073
+ console.log("\u{1F7E2} started session");
7074
+ const sessionStartEvent = {
7075
+ target: this,
7076
+ type: EventType.SessionStart
7077
+ };
7078
+ this.raiseEventOnListeners(sessionStartEvent);
6767
7079
  this.currentActivity = this.options.activities.find(Boolean);
6768
7080
  if (this.currentActivity) {
6769
7081
  DomHelpers.configureDomForActivity(this.currentActivity);
6770
7082
  await this.currentActivity.start();
7083
+ } else {
7084
+ console.warn("no activities in session.");
7085
+ this.end();
6771
7086
  }
6772
7087
  }
6773
7088
  /**
6774
7089
  * Declares the session ended and sends callback.
6775
7090
  */
6776
7091
  end() {
6777
- var _a;
6778
- const sessionLifecycleChangeCallback = (_a = this.options.sessionCallbacks) == null ? void 0 : _a.onSessionLifecycle;
6779
- if (sessionLifecycleChangeCallback) {
6780
- sessionLifecycleChangeCallback({
6781
- target: this,
6782
- type: EventType.SessionEnd
6783
- });
6784
- }
7092
+ console.log("\u{1F534} ended session");
6785
7093
  DomHelpers.hideAll();
6786
7094
  this.stop();
7095
+ const sessionEndEvent = {
7096
+ target: this,
7097
+ type: EventType.SessionEnd
7098
+ };
7099
+ this.raiseEventOnListeners(sessionEndEvent);
6787
7100
  }
6788
7101
  stop() {
6789
7102
  this.dispose();
@@ -6841,7 +7154,7 @@ class Session {
6841
7154
  this.fontManager.gameTypefaces[this.currentActivity.uuid] = this.fontManager.gameTypefaces[currentActivityOldObject.uuid];
6842
7155
  delete this.fontManager.gameTypefaces[currentActivityOldObject.uuid];
6843
7156
  }
6844
- await this.currentActivity.init();
7157
+ await this.currentActivity.initialize();
6845
7158
  await this.currentActivity.start();
6846
7159
  }
6847
7160
  /**
@@ -6857,10 +7170,8 @@ class Session {
6857
7170
  }
6858
7171
  this.currentActivity.stop();
6859
7172
  this.currentActivity = this.nextActivity;
6860
- if (this.currentActivity) {
6861
- DomHelpers.configureDomForActivity(this.currentActivity);
6862
- await this.currentActivity.start();
6863
- }
7173
+ DomHelpers.configureDomForActivity(this.currentActivity);
7174
+ await this.currentActivity.start();
6864
7175
  }
6865
7176
  /**
6866
7177
  * Stops the current activity and advances to next activity in the session.