@woosh/meep-engine 2.84.6 → 2.84.8

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.
@@ -61116,6 +61116,7 @@ function objectsEqual(a, b) {
61116
61116
  }
61117
61117
 
61118
61118
  /**
61119
+ * Works similarly to `Array.prototype.indexOf`, but instead of strict equality - uses provided equality method
61119
61120
  * @template T
61120
61121
  * @param {T[]} array
61121
61122
  * @param {T} element
@@ -61219,7 +61220,7 @@ class List {
61219
61220
  this.data = array !== undefined ? array.slice() : [];
61220
61221
 
61221
61222
  /**
61222
- *
61223
+ * Number of elements in the list
61223
61224
  * @type {number}
61224
61225
  */
61225
61226
  this.length = this.data.length;
@@ -61788,30 +61789,30 @@ class List {
61788
61789
  }
61789
61790
 
61790
61791
  /**
61791
- *
61792
+ * @deprecated use `#reset` directly in combination with `this.on.removed` signal
61792
61793
  * @param {function(element:T,index:number)} callback
61793
61794
  * @param {*} [thisArg]
61794
61795
  */
61795
61796
  resetViaCallback(callback, thisArg) {
61797
+
61796
61798
  const length = this.length;
61797
- if (length > 0) {
61798
61799
 
61799
- const removed = this.on.removed;
61800
+ const removed = this.on.removed;
61800
61801
 
61801
- const oldElements = this.data;
61802
+ const data = this.data;
61802
61803
 
61803
- //only signal if there are listeners attached
61804
- for (let i = length - 1; i >= 0; i--) {
61805
- const element = oldElements[i];
61806
- // decrement data length gradually to allow handlers access to the rest of the elements
61807
- this.data.length = i;
61808
- this.length = i;
61809
- removed.send2(element, i);
61804
+ for (let i = length - 1; i >= 0; i--) {
61805
+ const element = data[i];
61810
61806
 
61811
- callback.call(thisArg, element, i);
61812
- }
61807
+ // decrement data length gradually to allow handlers access to the rest of the elements
61808
+ data.length = i;
61809
+ this.length = i;
61810
+
61811
+ removed.send2(element, i);
61813
61812
 
61813
+ callback.call(thisArg, element, i);
61814
61814
  }
61815
+
61815
61816
  }
61816
61817
 
61817
61818
  reset() {
@@ -62031,11 +62032,19 @@ class List {
62031
62032
  }
62032
62033
 
62033
62034
  /**
62034
- *
62035
+ * First element in the list
62036
+ * @returns {T|undefined}
62037
+ */
62038
+ first() {
62039
+ return this.get(0);
62040
+ }
62041
+
62042
+ /**
62043
+ * Last element in the list
62035
62044
  * @return {T|undefined}
62036
62045
  */
62037
62046
  last() {
62038
- return this.data[this.length - 1];
62047
+ return this.get(this.length - 1);
62039
62048
  }
62040
62049
 
62041
62050
  /**
@@ -63119,10 +63128,11 @@ class WorkerProxy {
63119
63128
  }
63120
63129
 
63121
63130
  /**
63131
+ * Invoke a given method on the worker, as defined by the `WorkerBuilder`
63122
63132
  * @template T
63123
- * @param {number} name
63133
+ * @param {number} name Method's name
63124
63134
  * @param {Array} args
63125
- * @return {Promise<T>}
63135
+ * @return {Promise<T>} eventual result of the invoked method
63126
63136
  */
63127
63137
  $submitRequest(name, args) {
63128
63138
  const pending = this.__pending[name];
@@ -63345,6 +63355,10 @@ class WorkerBuilder {
63345
63355
  functions = [];
63346
63356
  preamble = new LineBuilder();
63347
63357
 
63358
+ /**
63359
+ *
63360
+ * @param {string} code
63361
+ */
63348
63362
  addCode(code) {
63349
63363
  this.preamble.add(code);
63350
63364
  }
@@ -79747,28 +79761,19 @@ function m3_cm_compose_transform(
79747
79761
  }
79748
79762
 
79749
79763
  /**
79750
- * @author Alex Goldring, 2018
79751
- * @copyright Alex Goldring 2018
79764
+ * Smallest safe increment for a Float32
79765
+ * @see https://www.cplusplus.com/reference/cfloat/
79766
+ * @see https://bitbashing.io/comparing-floats.html
79767
+ * @type {number}
79752
79768
  */
79753
-
79754
-
79755
-
79756
- const scratch_m3_0 = new Float32Array(9);
79757
-
79769
+ const FLT_EPSILON_32 = 1.192092896E-7;
79770
+
79758
79771
  /**
79759
- * @see https://dev.opera.com/articles/understanding-the-css-transforms-matrix/
79760
- * @param domElement
79761
- * @param {Vector2} position
79762
- * @param {Vector2} scale
79763
- * @param {number} rotation angle in radians
79772
+ *
79773
+ * @param {Float32Array} m3
79774
+ * @param {HTMLElement} domElement
79764
79775
  */
79765
- function setElementTransform(domElement, position, scale, rotation) {
79766
-
79767
- const m3 = scratch_m3_0;
79768
-
79769
- m3_cm_compose_transform(m3, position.x, position.y, scale.x, scale.y, 0, 0, rotation);
79770
-
79771
-
79776
+ function writeCssTransformMatrix(m3, domElement) {
79772
79777
  /*
79773
79778
  * CSS matrix is:
79774
79779
  * a c e
@@ -79788,7 +79793,13 @@ function setElementTransform(domElement, position, scale, rotation) {
79788
79793
  const style = domElement.style;
79789
79794
 
79790
79795
  style.transform = transform;
79791
- }
79796
+ }
79797
+
79798
+ /**
79799
+ * @author Alex Goldring, 2018
79800
+ * @copyright Alex Goldring 2018
79801
+ */
79802
+
79792
79803
 
79793
79804
  /**
79794
79805
  *
@@ -79827,6 +79838,9 @@ const INITIAL_FLAGS = ViewFlags.Visible;
79827
79838
  * @class
79828
79839
  */
79829
79840
  class View {
79841
+ #transform_written = new Float32Array(9);
79842
+ #transform_current = new Float32Array(9);
79843
+
79830
79844
  /**
79831
79845
  * @constructor
79832
79846
  */
@@ -79851,31 +79865,32 @@ class View {
79851
79865
  this.flags = INITIAL_FLAGS;
79852
79866
 
79853
79867
  /**
79854
- *
79868
+ * @readonly
79855
79869
  * @type {Vector2}
79856
79870
  */
79857
79871
  const position = this.position = new Vector2(0, 0);
79858
79872
 
79859
79873
  /**
79860
- *
79874
+ * @readonly
79861
79875
  * @type {Vector1}
79862
79876
  */
79863
79877
  const rotation = this.rotation = new Vector1(0);
79864
79878
 
79865
79879
  /**
79866
- *
79880
+ * @readonly
79867
79881
  * @type {Vector2}
79868
79882
  */
79869
79883
  const scale = this.scale = new Vector2(1, 1);
79870
79884
 
79871
79885
  /**
79872
- *
79886
+ * @readonly
79873
79887
  * @type {Vector2}
79874
79888
  */
79875
79889
  const size = this.size = new Vector2(0, 0);
79876
79890
 
79877
79891
  /**
79878
79892
  * Origin from which rotation and scaling is applied
79893
+ * @readonly
79879
79894
  * @type {Vector2}
79880
79895
  */
79881
79896
  this.transformOrigin = new Vector2(0.5, 0.5);
@@ -80013,7 +80028,41 @@ class View {
80013
80028
  * @private
80014
80029
  */
80015
80030
  __updateTransform() {
80016
- setElementTransform(this.el, this.position, this.scale, this.rotation.getValue());
80031
+ const position = this.position;
80032
+ const scale = this.scale;
80033
+ const rotation = this.rotation.getValue();
80034
+
80035
+ m3_cm_compose_transform(this.#transform_current, position.x, position.y, scale.x, scale.y, 0, 0, rotation);
80036
+
80037
+ this.#tryWriteTransform();
80038
+ }
80039
+
80040
+ #tryWriteTransform() {
80041
+
80042
+ const current = this.#transform_current;
80043
+ const written = this.#transform_written;
80044
+
80045
+ for (let i = 0; i < 9; i++) {
80046
+ const a = current[i];
80047
+ const b = written[i];
80048
+
80049
+ if (epsilonEquals(a, b, FLT_EPSILON_32)) {
80050
+ // common path
80051
+ continue;
80052
+ }
80053
+
80054
+ this.#writeTransform();
80055
+ return true;
80056
+
80057
+ }
80058
+
80059
+ return false;
80060
+ }
80061
+
80062
+ #writeTransform() {
80063
+ writeCssTransformMatrix(this.#transform_current, this.el);
80064
+
80065
+ this.#transform_written.set(this.#transform_current);
80017
80066
  }
80018
80067
 
80019
80068
  /**
@@ -93077,10 +93126,10 @@ class EntityComponentDataset {
93077
93126
 
93078
93127
  /**
93079
93128
  *
93080
- * @param {number} entityIndex
93129
+ * @param {number} entity_id
93081
93130
  */
93082
- removeEntity(entityIndex) {
93083
- if (!this.entityExists(entityIndex)) {
93131
+ removeEntity(entity_id) {
93132
+ if (!this.entityExists(entity_id)) {
93084
93133
  // entity doesn't exist
93085
93134
  return;
93086
93135
  }
@@ -93088,26 +93137,31 @@ class EntityComponentDataset {
93088
93137
  const componentOccupancy = this.componentOccupancy;
93089
93138
  const typeCount = this.componentTypeCount;
93090
93139
 
93091
- const occupancyStart = entityIndex * typeCount;
93140
+ const occupancyStart = entity_id * typeCount;
93092
93141
  const occupancyEnd = occupancyStart + typeCount;
93093
93142
 
93094
- for (let i = componentOccupancy.nextSetBit(occupancyStart); i < occupancyEnd && i !== -1; i = componentOccupancy.nextSetBit(i + 1)) {
93143
+ // remove all components from the entity
93144
+ for (
93145
+ let i = componentOccupancy.nextSetBit(occupancyStart);
93146
+ i < occupancyEnd && i !== -1;
93147
+ i = componentOccupancy.nextSetBit(i + 1)
93148
+ ) {
93095
93149
  const componentIndex = i % typeCount;
93096
- this.removeComponentFromEntityByIndex_Unchecked(entityIndex, componentIndex, i);
93150
+ this.removeComponentFromEntityByIndex_Unchecked(entity_id, componentIndex, i);
93097
93151
  }
93098
93152
 
93099
93153
  //dispatch event
93100
- this.sendEvent(entityIndex, EventType.EntityRemoved, entityIndex);
93154
+ this.sendEvent(entity_id, EventType.EntityRemoved, entity_id);
93101
93155
 
93102
93156
  //purge all event listeners
93103
- delete this.__entityEventListeners[entityIndex];
93104
- delete this.__entityAnyEventListeners[entityIndex];
93157
+ delete this.__entityEventListeners[entity_id];
93158
+ delete this.__entityAnyEventListeners[entity_id];
93105
93159
 
93106
- this.entityOccupancy.set(entityIndex, false);
93160
+ this.entityOccupancy.set(entity_id, false);
93107
93161
 
93108
93162
  this.entityCount--;
93109
93163
 
93110
- this.onEntityRemoved.send1(entityIndex);
93164
+ this.onEntityRemoved.send1(entity_id);
93111
93165
  }
93112
93166
 
93113
93167
  /**
@@ -93157,6 +93211,7 @@ class EntityComponentDataset {
93157
93211
  }
93158
93212
 
93159
93213
  /**
93214
+ * This method doesn't perform any checks, make sure you understand what you are doing when using it
93160
93215
  * @private
93161
93216
  * @param {number} entityIndex
93162
93217
  * @param {number} componentIndex
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "description": "Fully featured ECS game engine written in JavaScript",
6
6
  "type": "module",
7
7
  "author": "Alexander Goldring",
8
- "version": "2.84.6",
8
+ "version": "2.84.8",
9
9
  "main": "build/meep.module.js",
10
10
  "module": "build/meep.module.js",
11
11
  "exports": {
@@ -1,4 +1,5 @@
1
1
  /**
2
+ * Works similarly to `Array.prototype.indexOf`, but instead of strict equality - uses provided equality method
2
3
  * @template T
3
4
  * @param {T[]} array
4
5
  * @param {T} element
@@ -43,7 +43,7 @@ class List {
43
43
  this.data = array !== undefined ? array.slice() : [];
44
44
 
45
45
  /**
46
- *
46
+ * Number of elements in the list
47
47
  * @type {number}
48
48
  */
49
49
  this.length = this.data.length;
@@ -628,30 +628,30 @@ class List {
628
628
  }
629
629
 
630
630
  /**
631
- *
631
+ * @deprecated use `#reset` directly in combination with `this.on.removed` signal
632
632
  * @param {function(element:T,index:number)} callback
633
633
  * @param {*} [thisArg]
634
634
  */
635
635
  resetViaCallback(callback, thisArg) {
636
+
636
637
  const length = this.length;
637
- if (length > 0) {
638
638
 
639
- const removed = this.on.removed;
639
+ const removed = this.on.removed;
640
640
 
641
- const oldElements = this.data;
641
+ const data = this.data;
642
642
 
643
- //only signal if there are listeners attached
644
- for (let i = length - 1; i >= 0; i--) {
645
- const element = oldElements[i];
646
- // decrement data length gradually to allow handlers access to the rest of the elements
647
- this.data.length = i;
648
- this.length = i;
649
- removed.send2(element, i);
650
-
651
- callback.call(thisArg, element, i);
652
- }
643
+ for (let i = length - 1; i >= 0; i--) {
644
+ const element = data[i];
645
+
646
+ // decrement data length gradually to allow handlers access to the rest of the elements
647
+ data.length = i;
648
+ this.length = i;
653
649
 
650
+ removed.send2(element, i);
651
+
652
+ callback.call(thisArg, element, i);
654
653
  }
654
+
655
655
  }
656
656
 
657
657
  reset() {
@@ -875,11 +875,19 @@ class List {
875
875
  }
876
876
 
877
877
  /**
878
- *
878
+ * First element in the list
879
+ * @returns {T|undefined}
880
+ */
881
+ first() {
882
+ return this.get(0);
883
+ }
884
+
885
+ /**
886
+ * Last element in the list
879
887
  * @return {T|undefined}
880
888
  */
881
889
  last() {
882
- return this.data[this.length - 1];
890
+ return this.get(this.length - 1);
883
891
  }
884
892
 
885
893
  /**
@@ -9,6 +9,18 @@ class DummyNumber {
9
9
  equals(o) {
10
10
  return o.v === this.v;
11
11
  }
12
+
13
+ copy(other) {
14
+ this.v = other.v;
15
+ }
16
+
17
+ clone() {
18
+ const r = new DummyNumber();
19
+
20
+ r.copy(this);
21
+
22
+ return r;
23
+ }
12
24
  }
13
25
 
14
26
  test("constructor doesn't throw", () => {
@@ -254,4 +266,65 @@ test("patch", () => {
254
266
 
255
267
  expect(list.asArray()).toEqual([3, 1, 2]);
256
268
  expect(list.length).toBe(3);
269
+ });
270
+
271
+ test("equals", () => {
272
+
273
+ expect(
274
+ new List().equals(new List())
275
+ ).toBe(true);
276
+
277
+ expect(
278
+ new List(["a"]).equals(new List(["a"]))
279
+ ).toBe(true);
280
+
281
+ expect(
282
+ new List(["a"]).equals(new List(["b"]))
283
+ ).toBe(false);
284
+
285
+ expect(
286
+ new List(["a", "b"]).equals(new List(["a"]))
287
+ ).toBe(false);
288
+
289
+ expect(
290
+ new List(["a", "b"]).equals(new List(["b"]))
291
+ ).toBe(false);
292
+
293
+ expect(
294
+ new List(["a", "b"]).equals(new List(["a", "b"]))
295
+ ).toBe(true);
296
+
297
+ });
298
+
299
+ test("fist", () => {
300
+
301
+ expect(new List([1]).first()).toBe(1);
302
+ expect(new List([1, 2]).first()).toBe(1);
303
+
304
+ });
305
+ test("last", () => {
306
+
307
+ expect(new List([1]).last()).toBe(1);
308
+ expect(new List([1, 2]).last()).toBe(2);
309
+
310
+ });
311
+
312
+ test("deepCopy", () => {
313
+
314
+ const a = new List();
315
+ const b = new List();
316
+
317
+ b.deepCopy(a);
318
+
319
+ expect(b.isEmpty()).toBe(true);
320
+
321
+ const v = new DummyNumber(7);
322
+ b.addAll([v]);
323
+
324
+ a.deepCopy(b);
325
+
326
+ expect(a.length).toBe(1);
327
+ expect(a.first()).toBeDefined();
328
+ expect(a.first().v).toBe(7);
329
+ expect(a.first()).not.toBe(v);
257
330
  });
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
 
6
- import {convertPathToURL} from "../../../engine/network/convertPathToURL.js";
6
+ import { convertPathToURL } from "../../../engine/network/convertPathToURL.js";
7
7
  import LineBuilder from "../../codegen/LineBuilder.js";
8
8
  import WorkerProxy from "./WorkerProxy.js";
9
9
 
@@ -16,6 +16,10 @@ class WorkerBuilder {
16
16
  functions = [];
17
17
  preamble = new LineBuilder();
18
18
 
19
+ /**
20
+ *
21
+ * @param {string} code
22
+ */
19
23
  addCode(code) {
20
24
  this.preamble.add(code);
21
25
  }
@@ -66,10 +66,11 @@ class WorkerProxy {
66
66
  }
67
67
 
68
68
  /**
69
+ * Invoke a given method on the worker, as defined by the `WorkerBuilder`
69
70
  * @template T
70
- * @param {number} name
71
+ * @param {number} name Method's name
71
72
  * @param {Array} args
72
- * @return {Promise<T>}
73
+ * @return {Promise<T>} eventual result of the invoked method
73
74
  */
74
75
  $submitRequest(name, args) {
75
76
  const pending = this.__pending[name];
@@ -153,3 +153,36 @@ test("promiseEvent", async () => {
153
153
 
154
154
  await promise;
155
155
  });
156
+
157
+ test("generation correctly set for build", () => {
158
+
159
+ const entity = new Entity();
160
+
161
+ const ecd = sampleDataset();
162
+
163
+ entity.build(ecd);
164
+
165
+ expect(entity.generation).toEqual(ecd.getEntityGeneration(entity.id));
166
+
167
+ // rebuild
168
+ entity.destroy();
169
+
170
+ entity.build(ecd);
171
+
172
+ expect(entity.generation).toEqual(ecd.getEntityGeneration(entity.id));
173
+ });
174
+
175
+ test("generation correctly set when binding live entity", () => {
176
+
177
+
178
+ const ecd = sampleDataset();
179
+
180
+
181
+ const entity_a = ecd.createEntity();
182
+ const entity_b = ecd.createEntity();
183
+ const entity_c = ecd.createEntity();
184
+
185
+ const entity = Entity.readFromDataset(entity_b, ecd);
186
+
187
+ expect(entity.generation).toEqual(ecd.getEntityGeneration(entity_b));
188
+ });
@@ -836,10 +836,10 @@ export class EntityComponentDataset {
836
836
 
837
837
  /**
838
838
  *
839
- * @param {number} entityIndex
839
+ * @param {number} entity_id
840
840
  */
841
- removeEntity(entityIndex) {
842
- if (!this.entityExists(entityIndex)) {
841
+ removeEntity(entity_id) {
842
+ if (!this.entityExists(entity_id)) {
843
843
  // entity doesn't exist
844
844
  return;
845
845
  }
@@ -847,26 +847,31 @@ export class EntityComponentDataset {
847
847
  const componentOccupancy = this.componentOccupancy;
848
848
  const typeCount = this.componentTypeCount;
849
849
 
850
- const occupancyStart = entityIndex * typeCount;
850
+ const occupancyStart = entity_id * typeCount;
851
851
  const occupancyEnd = occupancyStart + typeCount;
852
852
 
853
- for (let i = componentOccupancy.nextSetBit(occupancyStart); i < occupancyEnd && i !== -1; i = componentOccupancy.nextSetBit(i + 1)) {
853
+ // remove all components from the entity
854
+ for (
855
+ let i = componentOccupancy.nextSetBit(occupancyStart);
856
+ i < occupancyEnd && i !== -1;
857
+ i = componentOccupancy.nextSetBit(i + 1)
858
+ ) {
854
859
  const componentIndex = i % typeCount;
855
- this.removeComponentFromEntityByIndex_Unchecked(entityIndex, componentIndex, i);
860
+ this.removeComponentFromEntityByIndex_Unchecked(entity_id, componentIndex, i);
856
861
  }
857
862
 
858
863
  //dispatch event
859
- this.sendEvent(entityIndex, EventType.EntityRemoved, entityIndex);
864
+ this.sendEvent(entity_id, EventType.EntityRemoved, entity_id);
860
865
 
861
866
  //purge all event listeners
862
- delete this.__entityEventListeners[entityIndex];
863
- delete this.__entityAnyEventListeners[entityIndex];
867
+ delete this.__entityEventListeners[entity_id];
868
+ delete this.__entityAnyEventListeners[entity_id];
864
869
 
865
- this.entityOccupancy.set(entityIndex, false);
870
+ this.entityOccupancy.set(entity_id, false);
866
871
 
867
872
  this.entityCount--;
868
873
 
869
- this.onEntityRemoved.send1(entityIndex);
874
+ this.onEntityRemoved.send1(entity_id);
870
875
  }
871
876
 
872
877
  /**
@@ -919,6 +924,7 @@ export class EntityComponentDataset {
919
924
  }
920
925
 
921
926
  /**
927
+ * This method doesn't perform any checks, make sure you understand what you are doing when using it
922
928
  * @private
923
929
  * @param {number} entityIndex
924
930
  * @param {number} componentIndex