@m2c2kit/core 0.3.10 → 0.3.12

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.
package/dist/index.js CHANGED
@@ -749,27 +749,28 @@ class Uuid {
749
749
  }
750
750
  }
751
751
 
752
- var EventType = /* @__PURE__ */ ((EventType2) => {
753
- EventType2["SessionInitialize"] = "SessionInitialize";
754
- EventType2["SessionStart"] = "SessionStart";
755
- EventType2["SessionEnd"] = "SessionEnd";
756
- EventType2["ActivityStart"] = "ActivityStart";
757
- EventType2["ActivityEnd"] = "ActivityEnd";
758
- EventType2["ActivityCancel"] = "ActivityCancel";
759
- EventType2["ActivityData"] = "ActivityData";
760
- EventType2["TapDown"] = "TapDown";
761
- EventType2["TapUp"] = "TapUp";
762
- EventType2["TapUpAny"] = "TapUpAny";
763
- EventType2["TapLeave"] = "TapLeave";
764
- EventType2["PointerDown"] = "PointerDown";
765
- EventType2["PointerUp"] = "PointerUp";
766
- EventType2["PointerMove"] = "PointerMove";
767
- EventType2["Drag"] = "Drag";
768
- EventType2["DragStart"] = "DragStart";
769
- EventType2["DragEnd"] = "DragEnd";
770
- EventType2["CompositeCustom"] = "CompositeCustom";
771
- return EventType2;
772
- })(EventType || {});
752
+ const EventType = {
753
+ SessionInitialize: "SessionInitialize",
754
+ SessionStart: "SessionStart",
755
+ SessionEnd: "SessionEnd",
756
+ ActivityStart: "ActivityStart",
757
+ ActivityEnd: "ActivityEnd",
758
+ ActivityCancel: "ActivityCancel",
759
+ ActivityData: "ActivityData",
760
+ TapDown: "TapDown",
761
+ TapUp: "TapUp",
762
+ TapUpAny: "TapUpAny",
763
+ TapLeave: "TapLeave",
764
+ PointerDown: "PointerDown",
765
+ PointerUp: "PointerUp",
766
+ PointerMove: "PointerMove",
767
+ PointerLeave: "PointerLeave",
768
+ Drag: "Drag",
769
+ DragStart: "DragStart",
770
+ DragEnd: "DragEnd",
771
+ CompositeCustom: "CompositeCustom",
772
+ FrameDidSimulatePhysics: "FrameDidSimulatePhysics"
773
+ };
773
774
 
774
775
  var __defProp$g = Object.defineProperty;
775
776
  var __defNormalProp$g = (obj, key, value) => key in obj ? __defProp$g(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -845,6 +846,7 @@ class Entity {
845
846
  /** Is the entity in a pressed state? E.g., did the user put the pointer
846
847
  * down on the entity and not yet release it? */
847
848
  __publicField$g(this, "pressed", false);
849
+ __publicField$g(this, "withinHitArea", false);
848
850
  /** Is the entity in a pressed state AND is the pointer within the entity's
849
851
  * hit area? For example, a user may put the pointer down on the entity, but
850
852
  * then move the pointer, while still down, beyond the entity's hit area. In
@@ -870,9 +872,9 @@ class Entity {
870
872
  type = this.compositeType;
871
873
  }
872
874
  if (this.name !== this.uuid) {
873
- return `"${this.name}" (${type}, ${this.uuid})`;
875
+ return `${this.name} (${type}, ${this.uuid})`;
874
876
  } else {
875
- return `"${type} (${this.uuid})`;
877
+ return `${type} (${this.uuid})`;
876
878
  }
877
879
  });
878
880
  if (options.name === void 0) {
@@ -920,32 +922,91 @@ class Entity {
920
922
  };
921
923
  return findParentScene(this).game;
922
924
  }
925
+ /**
926
+ * Determines if the entity has been added to the game object.
927
+ *
928
+ * @returns true if entity has been added
929
+ */
930
+ isPartOfGame() {
931
+ var _a;
932
+ if (this.type === EntityType.Scene && this._game === void 0) {
933
+ return false;
934
+ }
935
+ if (this.type === EntityType.Scene && this._game !== void 0) {
936
+ return true;
937
+ }
938
+ const findParentScene = (entity) => {
939
+ if (!entity.parent) {
940
+ return void 0;
941
+ } else if (entity.parent.type === EntityType.Scene) {
942
+ return entity.parent;
943
+ } else {
944
+ return findParentScene(entity.parent);
945
+ }
946
+ };
947
+ return ((_a = findParentScene(this)) == null ? void 0 : _a._game) !== void 0;
948
+ }
923
949
  /**
924
950
  * Adds a child to this parent entity. Throws exception if the child's name
925
- * is not unique with respect to other children of this parent.
951
+ * is not unique with respect to other children of this parent, or if the
952
+ * child has already been added to another parent.
926
953
  *
927
954
  * @param child - The child entity to add
928
955
  */
929
956
  addChild(child) {
957
+ if (child === this) {
958
+ throw new Error(
959
+ `Cannot add entity ${child.toString()} as a child to itself.`
960
+ );
961
+ }
930
962
  if (child.type == EntityType.Scene) {
931
963
  throw new Error(
932
- "A scene cannot be the child of an entity. A scene can only be added to a game object"
964
+ `Cannot add scene ${child.toString()} as a child to entity ${this.toString()}. A scene cannot be the child of an entity. A scene can only be added to a game object.`
965
+ );
966
+ }
967
+ if (this.children.filter((c) => c !== child).map((c) => c.name).includes(child.name)) {
968
+ throw new Error(
969
+ `Cannot add child entity ${child.toString()} to parent entity ${this.toString()}. A child with name "${child.name}" already exists on this parent.`
970
+ );
971
+ }
972
+ let otherParents = new Array();
973
+ if (this.isPartOfGame()) {
974
+ otherParents = this.game.entities.filter(
975
+ (e) => e.children.includes(child)
933
976
  );
977
+ } else {
978
+ const descendants = this.descendants;
979
+ if (descendants.includes(child)) {
980
+ otherParents = descendants.filter((d) => d.children.includes(child)).map((d) => {
981
+ var _a;
982
+ return (_a = d.parent) != null ? _a : void 0;
983
+ });
984
+ }
934
985
  }
935
- child.parent = this;
936
- if (this.children.map((c) => c.name).includes(child.name)) {
986
+ if (otherParents.length === 0) {
987
+ child.parent = this;
988
+ this.children.push(child);
989
+ return;
990
+ }
991
+ const firstOtherParent = otherParents.find(Boolean);
992
+ if (firstOtherParent === this) {
937
993
  throw new Error(
938
- `Cannot add child entity ${child.toString()} to parent entity ${this.toString()}. A child with name "${child.name}" already exists on parent.`
994
+ `Cannot add child entity ${child.toString()} to parent entity ${this.toString()}. This child already exists on this parent. The child cannot be added again.`
939
995
  );
940
996
  }
941
- this.children.push(child);
997
+ throw new Error(
998
+ `Cannot add child entity ${child.toString()} to parent entity ${this.toString()}. This child already exists on other parent entity: ${firstOtherParent == null ? void 0 : firstOtherParent.toString()}}. Remove the child from the other parent first.`
999
+ );
942
1000
  }
943
1001
  /**
944
1002
  * Removes all children from the entity.
945
1003
  */
946
1004
  removeAllChildren() {
947
1005
  while (this.children.length) {
948
- this.children.pop();
1006
+ const child = this.children.pop();
1007
+ if (child) {
1008
+ child.parent = void 0;
1009
+ }
949
1010
  }
950
1011
  }
951
1012
  /**
@@ -956,6 +1017,7 @@ class Entity {
956
1017
  */
957
1018
  removeChild(child) {
958
1019
  if (this.children.includes(child)) {
1020
+ child.parent = void 0;
959
1021
  this.children = this.children.filter((c) => c !== child);
960
1022
  } else {
961
1023
  throw new Error(
@@ -976,6 +1038,7 @@ class Entity {
976
1038
  `cannot remove entity ${child} from parent ${this} because the entity is not currently a child of the parent`
977
1039
  );
978
1040
  }
1041
+ child.parent = void 0;
979
1042
  });
980
1043
  this.children = this.children.filter((child) => !children.includes(child));
981
1044
  }
@@ -1068,17 +1131,13 @@ class Entity {
1068
1131
  * the bounds of the entity.
1069
1132
  *
1070
1133
  * @param callback - function to execute
1071
- * @param replaceExistingCallback - should the provided callback replace
1072
- * any existing callbacks of the same event type on this entity? Usually
1073
- * there should be only one callback defined, instead of chaining multiple
1074
- * ones. It is strongly recommended not to change this, unless you have a
1075
- * special use case. Default is true.
1134
+ * @param options - {@link CallbackOptions}
1076
1135
  */
1077
- onTapDown(callback, callbackOptions) {
1136
+ onTapDown(callback, options) {
1078
1137
  this.addEventListener(
1079
1138
  EventType.TapDown,
1080
1139
  callback,
1081
- callbackOptions
1140
+ options
1082
1141
  );
1083
1142
  }
1084
1143
  /**
@@ -1090,17 +1149,13 @@ class Entity {
1090
1149
  * beyond the bounds of the entity.
1091
1150
  *
1092
1151
  * @param callback - function to execute
1093
- * @param replaceExistingCallback - should the provided callback replace
1094
- * any existing callbacks of the same event type on this entity? Usually
1095
- * there should be only one callback defined, instead of chaining multiple
1096
- * ones. It is strongly recommended not to change this, unless you have a
1097
- * special use case. Default is true.
1152
+ * @param options - {@link CallbackOptions}ue.
1098
1153
  */
1099
- onTapUp(callback, callbackOptions) {
1154
+ onTapUp(callback, options) {
1100
1155
  this.addEventListener(
1101
1156
  EventType.TapUp,
1102
1157
  callback,
1103
- callbackOptions
1158
+ options
1104
1159
  );
1105
1160
  }
1106
1161
  /**
@@ -1113,17 +1168,13 @@ class Entity {
1113
1168
  * release.
1114
1169
  *
1115
1170
  * @param callback - function to execute
1116
- * @param replaceExistingCallback - should the provided callback replace
1117
- * any existing callbacks of the same event type on this entity? Usually
1118
- * there should be only one callback defined, instead of chaining multiple
1119
- * ones. It is strongly recommended not to change this, unless you have a
1120
- * special use case. Default is true.
1171
+ * @param options - {@link CallbackOptions}
1121
1172
  */
1122
- onTapUpAny(callback, callbackOptions) {
1173
+ onTapUpAny(callback, options) {
1123
1174
  this.addEventListener(
1124
1175
  EventType.TapUpAny,
1125
1176
  callback,
1126
- callbackOptions
1177
+ options
1127
1178
  );
1128
1179
  }
1129
1180
  /**
@@ -1135,17 +1186,13 @@ class Entity {
1135
1186
  * before the press release.
1136
1187
  *
1137
1188
  * @param callback - function to execute
1138
- * @param replaceExistingCallback - should the provided callback replace
1139
- * any existing callbacks of the same event type on this entity? Usually
1140
- * there should be only one callback defined, instead of chaining multiple
1141
- * ones. It is strongly recommended not to change this, unless you have a
1142
- * special use case. Default is true.
1189
+ * @param options - {@link CallbackOptions}
1143
1190
  */
1144
- onTapLeave(callback, callbackOptions) {
1191
+ onTapLeave(callback, options) {
1145
1192
  this.addEventListener(
1146
1193
  EventType.TapLeave,
1147
1194
  callback,
1148
- callbackOptions
1195
+ options
1149
1196
  );
1150
1197
  }
1151
1198
  /**
@@ -1155,17 +1202,13 @@ class Entity {
1155
1202
  * the bounds of the entity. It occurs under the same conditions as TapDown.
1156
1203
  *
1157
1204
  * @param callback - function to execute
1158
- * @param replaceExistingCallback - should the provided callback replace
1159
- * any existing callbacks of the same event type on this entity? Usually
1160
- * there should be only one callback defined, instead of chaining multiple
1161
- * ones. It is strongly recommended not to change this, unless you have a
1162
- * special use case. Default is true.
1205
+ * @param options - {@link CallbackOptions}
1163
1206
  */
1164
- onPointerDown(callback, callbackOptions) {
1207
+ onPointerDown(callback, options) {
1165
1208
  this.addEventListener(
1166
1209
  EventType.PointerDown,
1167
1210
  callback,
1168
- callbackOptions
1211
+ options
1169
1212
  );
1170
1213
  }
1171
1214
  /**
@@ -1177,17 +1220,13 @@ class Entity {
1177
1220
  * previous PointerDown on the entity.
1178
1221
  *
1179
1222
  * @param callback - function to execute
1180
- * @param replaceExistingCallback - should the provided callback replace
1181
- * any existing callbacks of the same event type on this entity? Usually
1182
- * there should be only one callback defined, instead of chaining multiple
1183
- * ones. It is strongly recommended not to change this, unless you have a
1184
- * special use case. Default is true.
1223
+ * @param options - {@link CallbackOptions}
1185
1224
  */
1186
- onPointerUp(callback, callbackOptions) {
1225
+ onPointerUp(callback, options) {
1187
1226
  this.addEventListener(
1188
1227
  EventType.PointerUp,
1189
1228
  callback,
1190
- callbackOptions
1229
+ options
1191
1230
  );
1192
1231
  }
1193
1232
  /**
@@ -1195,68 +1234,66 @@ class Entity {
1195
1234
  * within the bounds of the entity.
1196
1235
  *
1197
1236
  * @param callback - function to execute
1198
- * @param replaceExistingCallback - should the provided callback replace
1199
- * any existing callbacks of the same event type on this entity? Usually
1200
- * there should be only one callback defined, instead of chaining multiple
1201
- * ones. It is strongly recommended not to change this, unless you have a
1202
- * special use case. Default is true.
1237
+ * @param options - {@link CallbackOptions}
1203
1238
  */
1204
- onPointerMove(callback, callbackOptions) {
1239
+ onPointerMove(callback, options) {
1205
1240
  this.addEventListener(
1206
1241
  EventType.PointerMove,
1207
1242
  callback,
1208
- callbackOptions
1243
+ options
1244
+ );
1245
+ }
1246
+ /**
1247
+ * Executes a callback when the user moves the pointer (mouse or touches)
1248
+ * outside the bounds of the entity.
1249
+ *
1250
+ * @param callback - function to execute
1251
+ * @param options - {@link CallbackOptions}
1252
+ */
1253
+ onPointerLeave(callback, options) {
1254
+ this.addEventListener(
1255
+ EventType.PointerLeave,
1256
+ callback,
1257
+ options
1209
1258
  );
1210
1259
  }
1211
1260
  /**
1212
1261
  * Executes a callback when the user begins dragging an entity.
1213
1262
  *
1214
1263
  * @param callback - function to execute
1215
- * @param replaceExistingCallback - should the provided callback replace
1216
- * any existing callbacks of the same event type on this entity? Usually
1217
- * there should be only one callback defined, instead of chaining multiple
1218
- * ones. It is strongly recommended not to change this, unless you have a
1219
- * special use case. Default is true.
1264
+ * @param options - {@link CallbackOptions}
1220
1265
  */
1221
- onDragStart(callback, callbackOptions) {
1266
+ onDragStart(callback, options) {
1222
1267
  this.addEventListener(
1223
1268
  EventType.DragStart,
1224
1269
  callback,
1225
- callbackOptions
1270
+ options
1226
1271
  );
1227
1272
  }
1228
1273
  /**
1229
1274
  * Executes a callback when the user continues dragging an entity.
1230
1275
  *
1231
1276
  * @param callback - function to execute
1232
- * @param replaceExistingCallback - should the provided callback replace
1233
- * any existing callbacks of the same event type on this entity? Usually
1234
- * there should be only one callback defined, instead of chaining multiple
1235
- * ones. It is strongly recommended not to change this, unless you have a
1236
- * special use case. Default is true.
1277
+ * @param options - {@link CallbackOptions}
1237
1278
  */
1238
- onDrag(callback, callbackOptions) {
1279
+ onDrag(callback, options) {
1239
1280
  this.addEventListener(
1240
1281
  EventType.Drag,
1241
1282
  callback,
1242
- callbackOptions
1283
+ options
1243
1284
  );
1244
1285
  }
1245
1286
  /**
1246
1287
  * Executes a callback when the user stop dragging an entity.
1247
1288
  *
1248
1289
  * @param callback - function to execute
1249
- * @param replaceExistingCallback - should the provided callback replace
1250
- * any existing callbacks of the same event type on this entity? Usually
1251
- * there should be only one callback defined, instead of chaining multiple
1252
- * ones. It is strongly recommended not to change this, unless you have a
1253
- * special use case. Default is true.
1290
+ * @param options - {@link CallbackOptions}
1254
1291
  */
1255
- onDragEnd(callback, callbackOptions) {
1292
+ onDragEnd(callback, options) {
1256
1293
  this.addEventListener(
1257
1294
  EventType.DragEnd,
1258
1295
  callback,
1259
- callbackOptions
1296
+ options
1260
1297
  );
1261
1298
  }
1262
1299
  addEventListener(type, callback, callbackOptions) {
@@ -3243,7 +3280,7 @@ class Game {
3243
3280
  __publicField$6(this, "i18n");
3244
3281
  __publicField$6(this, "warmupFunctionQueue", new Array());
3245
3282
  __publicField$6(this, "loaderElementsRemoved", false);
3246
- __publicField$6(this, "_dataStore");
3283
+ __publicField$6(this, "_dataStores");
3247
3284
  __publicField$6(this, "additionalParameters");
3248
3285
  __publicField$6(this, "staticTrialSchema", {});
3249
3286
  /** The scene, or its name as a string, to be presented when the game is started. If this is undefined, the game will start with the first scene that has been added */
@@ -3359,12 +3396,13 @@ class Game {
3359
3396
  * Saves an item to the activity's key-value store.
3360
3397
  *
3361
3398
  * @remarks The underlying persistence provider of the key-value store must
3362
- * be previously set in the activity's `Session` before use:
3363
- * ```
3364
- * const db: IDataStore = new LocalDatabase();
3365
- * session.dataStore = db;
3366
- * session.initialize();
3367
- * ```
3399
+ * have been previously provided in `SessionOptions`.
3400
+ * @example
3401
+ * import { LocalDatabase } from "@m2c2kit/db";
3402
+ * const session = new Session({
3403
+ * dataStores: [new LocalDatabase()]
3404
+ * ...
3405
+ * });
3368
3406
  * @param key - item key
3369
3407
  * @param value - item value
3370
3408
  * @param globalStore - if true, treat the item as "global" and not
@@ -3375,18 +3413,19 @@ class Game {
3375
3413
  storeSetItem(key, value, globalStore = false) {
3376
3414
  const k = globalStore ? key : this.id.concat(":", key);
3377
3415
  const activityId = globalStore ? "" : this.id;
3378
- return this.dataStore.setItem(k, value, activityId);
3416
+ return this.dataStores[0].setItem(k, value, activityId);
3379
3417
  }
3380
3418
  /**
3381
3419
  * Gets an item value from the activity's key-value store.
3382
3420
  *
3383
3421
  * @remarks The underlying persistence provider of the key-value store must
3384
- * be previously set in the activity's `Session` before use:
3385
- * ```
3386
- * const db: IDataStore = new LocalDatabase();
3387
- * session.dataStore = db;
3388
- * session.initialize();
3389
- * ```
3422
+ * have been previously provided in `SessionOptions`.
3423
+ * @example
3424
+ * import { LocalDatabase } from "@m2c2kit/db";
3425
+ * const session = new Session({
3426
+ * dataStores: [new LocalDatabase()]
3427
+ * ...
3428
+ * });
3390
3429
  * @param key - item key
3391
3430
  * @param globalStore - if true, treat the item as "global" and not
3392
3431
  * associated with a specific activity; global items can be accessed
@@ -3395,18 +3434,19 @@ class Game {
3395
3434
  */
3396
3435
  storeGetItem(key, globalStore = false) {
3397
3436
  const k = globalStore ? key : this.id.concat(":", key);
3398
- return this.dataStore.getItem(k);
3437
+ return this.dataStores[0].getItem(k);
3399
3438
  }
3400
3439
  /**
3401
3440
  * Deletes an item value from the activity's key-value store.
3402
3441
  *
3403
3442
  * @remarks The underlying persistence provider of the key-value store must
3404
- * be previously set in the activity's `Session` before use:
3405
- * ```
3406
- * const db: IDataStore = new LocalDatabase();
3407
- * session.dataStore = db;
3408
- * session.initialize();
3409
- * ```
3443
+ * have been previously provided in `SessionOptions`.
3444
+ * @example
3445
+ * import { LocalDatabase } from "@m2c2kit/db";
3446
+ * const session = new Session({
3447
+ * dataStores: [new LocalDatabase()]
3448
+ * ...
3449
+ * });
3410
3450
  * @param key - item key
3411
3451
  * @param globalStore - if true, treat the item as "global" and not
3412
3452
  * associated with a specific activity; global items can be accessed
@@ -3414,49 +3454,52 @@ class Game {
3414
3454
  */
3415
3455
  storeDeleteItem(key, globalStore = false) {
3416
3456
  const k = globalStore ? key : this.id.concat(":", key);
3417
- return this.dataStore.deleteItem(k);
3457
+ return this.dataStores[0].deleteItem(k);
3418
3458
  }
3419
3459
  /**
3420
3460
  * Deletes all items from the activity's key-value store.
3421
3461
  *
3422
3462
  * @remarks The underlying persistence provider of the key-value store must
3423
- * be previously set in the activity's `Session` before use:
3424
- * ```
3425
- * const db: IDataStore = new LocalDatabase();
3426
- * session.dataStore = db;
3427
- * session.initialize();
3428
- * ```
3463
+ * have been previously provided in `SessionOptions`.
3464
+ * @example
3465
+ * import { LocalDatabase } from "@m2c2kit/db";
3466
+ * const session = new Session({
3467
+ * dataStores: [new LocalDatabase()]
3468
+ * ...
3469
+ * });
3429
3470
  */
3430
3471
  storeClearItems() {
3431
- return this.dataStore.clearItemsByActivityId(this.id);
3472
+ return this.dataStores[0].clearItemsByActivityId(this.id);
3432
3473
  }
3433
3474
  /**
3434
3475
  * Returns keys of all items in the activity's key-value store.
3435
3476
  *
3436
3477
  * @remarks The underlying persistence provider of the key-value store must
3437
- * be previously set in the activity's `Session` before use:
3438
- * ```
3439
- * const db: IDataStore = new LocalDatabase();
3440
- * session.dataStore = db;
3441
- * session.initialize();
3442
- * ```
3478
+ * have been previously provided in `SessionOptions`.
3479
+ * @example
3480
+ * import { LocalDatabase } from "@m2c2kit/db";
3481
+ * const session = new Session({
3482
+ * dataStores: [new LocalDatabase()]
3483
+ * ...
3484
+ * });
3443
3485
  * @param globalStore - if true, treat the item as "global" and not
3444
3486
  * associated with a specific activity; global items can be accessed
3445
3487
  * by any activity. Default is false.
3446
3488
  */
3447
3489
  storeItemsKeys(globalStore = false) {
3448
- return this.dataStore.itemsKeysByActivityId(globalStore ? "" : this.id);
3490
+ return this.dataStores[0].itemsKeysByActivityId(globalStore ? "" : this.id);
3449
3491
  }
3450
3492
  /**
3451
3493
  * Determines if a key exists in the activity's key-value store.
3452
3494
  *
3453
3495
  * @remarks The underlying persistence provider of the key-value store must
3454
- * be previously set in the activity's `Session` before use:
3455
- * ```
3456
- * const db: IDataStore = new LocalDatabase();
3457
- * session.dataStore = db;
3458
- * session.initialize();
3459
- * ```
3496
+ * have been previously provided in `SessionOptions`.
3497
+ * @example
3498
+ * import { LocalDatabase } from "@m2c2kit/db";
3499
+ * const session = new Session({
3500
+ * dataStores: [new LocalDatabase()]
3501
+ * ...
3502
+ * });
3460
3503
  * @param key - item key
3461
3504
  * @param globalStore - if true, treat the item as "global" and not
3462
3505
  * associated with a specific activity; global items can be accessed
@@ -3465,16 +3508,16 @@ class Game {
3465
3508
  */
3466
3509
  storeItemExists(key, globalStore = false) {
3467
3510
  const k = globalStore ? key : this.id.concat(":", key);
3468
- return this.dataStore.itemExists(k);
3511
+ return this.dataStores[0].itemExists(k);
3469
3512
  }
3470
- get dataStore() {
3471
- if (!this._dataStore) {
3472
- throw new Error("dataStore is undefined");
3513
+ get dataStores() {
3514
+ if (!this._dataStores) {
3515
+ throw new Error("dataStores is undefined");
3473
3516
  }
3474
- return this._dataStore;
3517
+ return this._dataStores;
3475
3518
  }
3476
- set dataStore(dataStore) {
3477
- this._dataStore = dataStore;
3519
+ set dataStores(dataStores) {
3520
+ this._dataStores = dataStores;
3478
3521
  }
3479
3522
  getLocalizationOptionsFromGameParameters() {
3480
3523
  const locale = this.getParameter("locale");
@@ -4688,9 +4731,28 @@ class Game {
4688
4731
  outgoingScene.addChild(spr);
4689
4732
  return outgoingScene;
4690
4733
  }
4734
+ /**
4735
+ * Executes a callback when the frame has finished simulating physics.
4736
+ *
4737
+ * @param callback - function to execute.
4738
+ * @param options - options for the callback.
4739
+ */
4740
+ onFrameDidSimulatePhysics(callback, options) {
4741
+ this.addEventListener(
4742
+ EventType.FrameDidSimulatePhysics,
4743
+ callback,
4744
+ options
4745
+ );
4746
+ }
4691
4747
  update() {
4692
4748
  this.scenes.filter((scene) => scene._active).forEach((scene) => scene.update());
4693
4749
  this.freeEntitiesScene.update();
4750
+ const frameDidSimulatePhysicsEvent = {
4751
+ target: this,
4752
+ type: EventType.FrameDidSimulatePhysics,
4753
+ deltaTime: Globals.deltaTime
4754
+ };
4755
+ this.raiseActivityEventOnListeners(frameDidSimulatePhysicsEvent);
4694
4756
  }
4695
4757
  draw(canvas) {
4696
4758
  this.scenes.filter((scene) => scene._active).forEach((scene) => scene.draw(canvas));
@@ -5251,6 +5313,17 @@ class Game {
5251
5313
  domPointerEvent.offsetY
5252
5314
  )) {
5253
5315
  this.raiseM2PointerMoveEvent(entity, m2Event, domPointerEvent);
5316
+ entity.withinHitArea = true;
5317
+ }
5318
+ if (!this.IsCanvasPointWithinEntityBounds(
5319
+ entity,
5320
+ domPointerEvent.offsetX,
5321
+ domPointerEvent.offsetY
5322
+ )) {
5323
+ if (entity.withinHitArea) {
5324
+ this.raiseM2PointerLeaveEvent(entity, m2Event, domPointerEvent);
5325
+ entity.withinHitArea = false;
5326
+ }
5254
5327
  }
5255
5328
  if (entity.children) {
5256
5329
  entity.children.filter((entity2) => !entity2.hidden).filter((entity2) => entity2.isDrawable).sort(
@@ -5323,6 +5396,15 @@ class Game {
5323
5396
  domPointerEvent
5324
5397
  );
5325
5398
  }
5399
+ raiseM2PointerLeaveEvent(entity, m2Event, domPointerEvent) {
5400
+ m2Event.target = entity;
5401
+ m2Event.type = EventType.PointerLeave;
5402
+ this.raiseEventOnListeningEntities(
5403
+ entity,
5404
+ m2Event,
5405
+ domPointerEvent
5406
+ );
5407
+ }
5326
5408
  raiseM2DragStartEvent(entity, m2Event, domPointerEvent) {
5327
5409
  m2Event.target = entity;
5328
5410
  m2Event.type = EventType.DragStart;
@@ -5437,6 +5519,7 @@ class Game {
5437
5519
  case EventType.PointerDown:
5438
5520
  case EventType.PointerMove:
5439
5521
  case EventType.PointerUp:
5522
+ case EventType.PointerLeave:
5440
5523
  m2Event.point = this.calculatePointWithinEntityFromDomPointerEvent(
5441
5524
  entity,
5442
5525
  domEvent
@@ -5495,11 +5578,14 @@ class Game {
5495
5578
  if (!radius) {
5496
5579
  throw "circleOfRadius is undefined";
5497
5580
  }
5498
- const center = { x: bb2.xMin + radius, y: bb2.yMin + radius };
5581
+ const center = {
5582
+ x: bb2.xMin + radius * entity.absoluteScale,
5583
+ y: bb2.yMin + radius * entity.absoluteScale
5584
+ };
5499
5585
  const distance = Math.sqrt(
5500
5586
  Math.pow(x - center.x, 2) + Math.pow(y - center.y, 2)
5501
5587
  );
5502
- return distance <= radius;
5588
+ return distance <= radius * entity.absoluteScale;
5503
5589
  }
5504
5590
  if (entity.size.width === 0 || entity.size.height === 0) {
5505
5591
  return false;
@@ -7012,12 +7098,12 @@ class Session {
7012
7098
  __publicField$2(this, "imageManager");
7013
7099
  __publicField$2(this, "currentActivity");
7014
7100
  __publicField$2(this, "uuid");
7015
- __publicField$2(this, "dataStore");
7101
+ __publicField$2(this, "dataStores");
7016
7102
  __publicField$2(this, "eventListeners", new Array());
7017
7103
  __publicField$2(this, "sessionDictionary", /* @__PURE__ */ new Map());
7018
7104
  __publicField$2(this, "canvasKit");
7019
7105
  __publicField$2(this, "initialized", false);
7020
- __publicField$2(this, "version", "0.3.10 (b15b374e)");
7106
+ __publicField$2(this, "version", "0.3.12 (291d0cee)");
7021
7107
  this.options = options;
7022
7108
  for (const activity of this.options.activities) {
7023
7109
  if (this.options.activities.filter((a) => a === activity).length > 1) {
@@ -7184,6 +7270,7 @@ class Session {
7184
7270
  * Asynchronously initializes the m2c2kit engine and loads assets
7185
7271
  */
7186
7272
  async initialize() {
7273
+ var _a;
7187
7274
  console.log(`\u26AA @m2c2kit/core version ${this.version}`);
7188
7275
  Timer.start("sessionInitialize");
7189
7276
  const sessionInitializeEvent = {
@@ -7194,9 +7281,15 @@ class Session {
7194
7281
  DomHelpers.addLoadingElements();
7195
7282
  DomHelpers.setSpinnerVisibility(true);
7196
7283
  DomHelpers.setCanvasOverlayVisibility(true);
7284
+ this.dataStores = this.options.dataStores;
7285
+ if (((_a = this.dataStores) == null ? void 0 : _a.length) === 0) {
7286
+ throw new Error(
7287
+ "Session.initialize(): dataStores must be undefined or a non-zero array of datastores."
7288
+ );
7289
+ }
7197
7290
  await Promise.all(
7198
7291
  this.options.activities.map((activity) => {
7199
- activity.dataStore = this.dataStore;
7292
+ activity.dataStores = this.dataStores;
7200
7293
  activity.onStart(this.sessionActivityLifecycleHandler.bind(this));
7201
7294
  activity.onCancel(this.sessionActivityLifecycleHandler.bind(this));
7202
7295
  activity.onEnd(this.sessionActivityLifecycleHandler.bind(this));
@@ -7322,7 +7415,7 @@ class Session {
7322
7415
  this.options.activities[indexOfCurrentActivity] = this.currentActivity;
7323
7416
  DomHelpers.configureDomForActivity(this.currentActivity);
7324
7417
  this.currentActivity.session = this;
7325
- this.currentActivity.dataStore = this.dataStore;
7418
+ this.currentActivity.dataStores = this.dataStores;
7326
7419
  if (this.currentActivity.type === ActivityType.Game && this.canvasKit) {
7327
7420
  this.currentActivity.canvasKit = this.canvasKit;
7328
7421
  }
@@ -7527,7 +7620,6 @@ class Shape extends Entity {
7527
7620
  * @param options - {@link ShapeOptions}
7528
7621
  */
7529
7622
  constructor(options = {}) {
7530
- var _a;
7531
7623
  super(options);
7532
7624
  __publicField$1(this, "type", EntityType.Shape);
7533
7625
  __publicField$1(this, "isDrawable", true);
@@ -7544,7 +7636,6 @@ class Shape extends Entity {
7544
7636
  __publicField$1(this, "ckPath", null);
7545
7637
  __publicField$1(this, "ckPathWidth");
7546
7638
  __publicField$1(this, "ckPathHeight");
7547
- __publicField$1(this, "pathSvgString");
7548
7639
  __publicField$1(this, "cornerRadius", 0);
7549
7640
  __publicField$1(this, "_fillColor", Constants.DEFAULT_SHAPE_FILL_COLOR);
7550
7641
  __publicField$1(this, "_strokeColor");
@@ -7559,15 +7650,17 @@ class Shape extends Entity {
7559
7650
  __publicField$1(this, "svgPathScaleForResizing", 1);
7560
7651
  __publicField$1(this, "svgPathWidth", 0);
7561
7652
  __publicField$1(this, "svgPathHeight", 0);
7562
- __publicField$1(this, "svgPreviousAbsoluteScale", NaN);
7563
7653
  __publicField$1(this, "svgPreviousAbsoluteX", NaN);
7564
7654
  __publicField$1(this, "svgPreviousAbsoluteY", NaN);
7565
- __publicField$1(this, "pathIsSvgStringPath", false);
7655
+ __publicField$1(this, "svgFirstPathDraw", true);
7566
7656
  handleInterfaceOptions(this, options);
7567
- if (((_a = options == null ? void 0 : options.path) == null ? void 0 : _a.svgPathString) !== void 0) {
7657
+ if (options.path !== void 0) {
7658
+ this.path = options.path;
7568
7659
  this.shapeType = ShapeType.Path;
7569
- this.pathIsSvgStringPath = true;
7570
- this.pathSvgString = options.path.svgPathString;
7660
+ if (this.path.size !== void 0) {
7661
+ this.size.height = this.path.size.height;
7662
+ this.size.width = this.path.size.width;
7663
+ }
7571
7664
  this.svgPathRequestedWidth = options.path.width;
7572
7665
  this.svgPathRequestedHeight = options.path.height;
7573
7666
  if (this.svgPathRequestedHeight !== void 0 && this.svgPathRequestedWidth !== void 0) {
@@ -7645,28 +7738,29 @@ class Shape extends Entity {
7645
7738
  }
7646
7739
  }
7647
7740
  initialize() {
7648
- var _a, _b;
7649
- if (this.shapeType === ShapeType.Path && this.pathIsSvgStringPath) {
7650
- if (!this.pathSvgString) {
7651
- throw new Error("SVG Path string is null/undefined");
7652
- }
7653
- this.ckPath = this.canvasKit.Path.MakeFromSVGString(this.pathSvgString);
7654
- if (!this.ckPath) {
7655
- throw new Error("could not make CanvasKit Path from SVG string");
7656
- }
7657
- const bounds = this.ckPath.getBounds();
7658
- this.svgPathWidth = bounds[2] + (bounds[0] < 0 ? Math.abs(bounds[0]) : 0);
7659
- this.svgPathHeight = bounds[3] + (bounds[1] < 0 ? Math.abs(bounds[1]) : 0);
7660
- this.size.width = (_a = this.size.width) != null ? _a : this.svgPathWidth;
7661
- this.size.height = (_b = this.size.height) != null ? _b : this.svgPathHeight;
7662
- if (this.svgPathRequestedHeight !== void 0) {
7663
- this.svgPathScaleForResizing = this.svgPathRequestedHeight / this.svgPathHeight;
7664
- } else if (this.svgPathRequestedWidth !== void 0) {
7665
- this.svgPathScaleForResizing = this.svgPathRequestedWidth / this.svgPathWidth;
7666
- }
7667
- this.svgPreviousAbsoluteScale = 1;
7668
- this.svgPreviousAbsoluteX = 0;
7669
- this.svgPreviousAbsoluteY = 0;
7741
+ if (this.shapeType === ShapeType.Path) {
7742
+ if (this.shapeIsSvgStringPath()) {
7743
+ const pathSvgString = this.path.svgPathString;
7744
+ if (!pathSvgString) {
7745
+ throw new Error("SVG Path string is null/undefined");
7746
+ }
7747
+ this.ckPath = this.canvasKit.Path.MakeFromSVGString(pathSvgString);
7748
+ if (!this.ckPath) {
7749
+ throw new Error("could not make CanvasKit Path from SVG string");
7750
+ }
7751
+ const bounds = this.ckPath.getBounds();
7752
+ this.svgPathWidth = bounds[2] + (bounds[0] < 0 ? Math.abs(bounds[0]) : 0);
7753
+ this.svgPathHeight = bounds[3] + (bounds[1] < 0 ? Math.abs(bounds[1]) : 0);
7754
+ if (this.svgPathRequestedHeight !== void 0) {
7755
+ this.svgPathScaleForResizing = this.svgPathRequestedHeight / this.svgPathHeight;
7756
+ } else if (this.svgPathRequestedWidth !== void 0) {
7757
+ this.svgPathScaleForResizing = this.svgPathRequestedWidth / this.svgPathWidth;
7758
+ }
7759
+ this.size.width = this.svgPathWidth * this.svgPathScaleForResizing;
7760
+ this.size.height = this.svgPathHeight * this.svgPathScaleForResizing;
7761
+ this.svgPreviousAbsoluteX = 0;
7762
+ this.svgPreviousAbsoluteY = 0;
7763
+ }
7670
7764
  }
7671
7765
  if (this.fillColor) {
7672
7766
  this.fillColorPaintAntialiased = CanvasKitHelpers.makePaint(
@@ -7696,6 +7790,7 @@ class Shape extends Entity {
7696
7790
  false
7697
7791
  );
7698
7792
  }
7793
+ this.svgFirstPathDraw = true;
7699
7794
  this.needsInitialization = false;
7700
7795
  }
7701
7796
  dispose() {
@@ -7744,10 +7839,10 @@ class Shape extends Entity {
7744
7839
  canvas.save();
7745
7840
  const drawScale = Globals.canvasScale / this.absoluteScale;
7746
7841
  canvas.scale(1 / drawScale, 1 / drawScale);
7747
- if (this.shapeType === ShapeType.Path && !this.pathIsSvgStringPath) {
7842
+ if (this.shapeIsM2Path()) {
7748
7843
  this.drawPathFromM2Path(canvas);
7749
7844
  }
7750
- if (this.shapeType === ShapeType.Path && this.pathIsSvgStringPath) {
7845
+ if (this.shapeIsSvgStringPath()) {
7751
7846
  this.drawPathFromSvgString(canvas);
7752
7847
  }
7753
7848
  if (this.shapeType === ShapeType.Circle) {
@@ -7764,18 +7859,16 @@ class Shape extends Entity {
7764
7859
  const pathOriginX = (this.absolutePosition.x - this.anchorPoint.x * this.size.width * this.absoluteScale) * drawScale;
7765
7860
  const pathOriginY = (this.absolutePosition.y - this.anchorPoint.y * this.size.height * this.absoluteScale) * drawScale;
7766
7861
  if (this.strokeColor && this.strokeColorPaintAntialiased && this.lineWidth) {
7767
- this.strokeColorPaintAntialiased.setStrokeWidth(
7768
- this.lineWidth * drawScale
7769
- );
7862
+ this.strokeColorPaintAntialiased.setStrokeWidth(this.lineWidth);
7770
7863
  const subpaths = this.path.subpaths;
7771
7864
  for (const subpath of subpaths) {
7772
7865
  const points = subpath.flat();
7773
7866
  for (let i = 0; i < points.length - 1; i++) {
7774
7867
  canvas.drawLine(
7775
- pathOriginX + points[i].x * drawScale,
7776
- pathOriginY + points[i].y * drawScale,
7777
- pathOriginX + points[i + 1].x * drawScale,
7778
- pathOriginY + points[i + 1].y * drawScale,
7868
+ pathOriginX + points[i].x * Globals.canvasScale,
7869
+ pathOriginY + points[i].y * Globals.canvasScale,
7870
+ pathOriginX + points[i + 1].x * Globals.canvasScale,
7871
+ pathOriginY + points[i + 1].y * Globals.canvasScale,
7779
7872
  this.strokeColorPaintAntialiased
7780
7873
  );
7781
7874
  }
@@ -7788,12 +7881,12 @@ class Shape extends Entity {
7788
7881
  }
7789
7882
  const x = this.calculateSvgPathX();
7790
7883
  const y = this.calculateSvgPathY();
7791
- const drawScale = Globals.canvasScale / this.absoluteScale;
7792
- const pathScale = drawScale * this.svgPathScaleForResizing * Globals.rootScale;
7793
- if (this.pathNeedsTransform(pathScale, x, y)) {
7884
+ if (this.pathNeedsTransform(x, y)) {
7885
+ const drawScale = Globals.canvasScale / this.absoluteScale;
7886
+ const pathScale = drawScale * this.svgPathScaleForResizing * Globals.rootScale;
7794
7887
  const matrix = this.calculateTransformationMatrix(pathScale, x, y);
7795
7888
  this.ckPath = this.ckPath.transform(matrix);
7796
- this.saveSvgPathDrawParameters(pathScale, x, y);
7889
+ this.saveSvgPathAbsolutePosition(x, y);
7797
7890
  }
7798
7891
  if (this.fillColor) {
7799
7892
  const paint = this.getFillPaint();
@@ -7806,25 +7899,38 @@ class Shape extends Entity {
7806
7899
  }
7807
7900
  calculateSvgPathY() {
7808
7901
  const drawScale = Globals.canvasScale / this.absoluteScale;
7809
- return (this.absolutePosition.y + (this.size.height - this.svgPathHeight * this.svgPathScaleForResizing * Globals.rootScale) / 2 - this.anchorPoint.y * this.size.height) * drawScale;
7902
+ return (this.absolutePosition.y - this.size.height * this.absoluteScale / 2) * drawScale;
7810
7903
  }
7811
7904
  calculateSvgPathX() {
7812
7905
  const drawScale = Globals.canvasScale / this.absoluteScale;
7813
- return (this.absolutePosition.x + (this.size.width - this.svgPathWidth * this.svgPathScaleForResizing * Globals.rootScale) / 2 - this.anchorPoint.x * this.size.width) * drawScale;
7906
+ return (this.absolutePosition.x - this.size.width * this.absoluteScale / 2) * drawScale;
7814
7907
  }
7815
- saveSvgPathDrawParameters(pathScale, x, y) {
7816
- this.svgPreviousAbsoluteScale = pathScale;
7908
+ saveSvgPathAbsolutePosition(x, y) {
7817
7909
  this.svgPreviousAbsoluteX = x;
7818
7910
  this.svgPreviousAbsoluteY = y;
7819
7911
  }
7820
7912
  calculateTransformationMatrix(pathScale, x, y) {
7821
- const dScale = pathScale / this.svgPreviousAbsoluteScale;
7913
+ let dScale;
7914
+ if (this.svgFirstPathDraw) {
7915
+ dScale = pathScale;
7916
+ this.svgFirstPathDraw = false;
7917
+ } else {
7918
+ dScale = 1;
7919
+ }
7822
7920
  const dX = x - this.svgPreviousAbsoluteX;
7823
7921
  const dY = y - this.svgPreviousAbsoluteY;
7824
7922
  return [dScale, 0, dX, 0, dScale, dY, 0, 0, 1];
7825
7923
  }
7826
- pathNeedsTransform(pathScale, x, y) {
7827
- return pathScale !== this.svgPreviousAbsoluteScale || x !== this.svgPreviousAbsoluteX || y !== this.svgPreviousAbsoluteY;
7924
+ pathNeedsTransform(x, y) {
7925
+ return this.svgFirstPathDraw === true || x !== this.svgPreviousAbsoluteX || y !== this.svgPreviousAbsoluteY;
7926
+ }
7927
+ shapeIsSvgStringPath() {
7928
+ var _a;
7929
+ return ((_a = this.path) == null ? void 0 : _a.svgPathString) !== void 0;
7930
+ }
7931
+ shapeIsM2Path() {
7932
+ var _a;
7933
+ return ((_a = this.path) == null ? void 0 : _a.subpaths) !== void 0;
7828
7934
  }
7829
7935
  drawCircle(canvas) {
7830
7936
  if (!this.circleOfRadius) {