@woosh/meep-engine 2.48.17 → 2.48.19

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 (48) hide show
  1. package/package.json +1 -1
  2. package/src/core/binary/dec2hex.spec.js +13 -0
  3. package/src/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.d.ts +18 -0
  4. package/src/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.js +18 -0
  5. package/src/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.spec.js +56 -0
  6. package/src/core/cache/Cache.d.ts +5 -0
  7. package/src/core/cache/Cache.js +8 -1
  8. package/src/core/cache/Cache.spec.js +47 -3
  9. package/src/core/codegen/LineBuilder.js +117 -106
  10. package/src/core/collection/HashMap.spec.js +32 -0
  11. package/src/core/collection/list/List.js +6 -4
  12. package/src/core/geom/Matrix4.js +4 -1
  13. package/src/core/geom/Quaternion.js +4 -0
  14. package/src/core/geom/Vector3.js +9 -31
  15. package/src/core/graph/Edge.js +11 -2
  16. package/src/core/graph/v2/Graph.js +36 -31
  17. package/src/core/graph/v2/Graph.spec.js +309 -1
  18. package/src/core/math/fract.spec.js +11 -0
  19. package/src/core/math/isPowerOfTwo.spec.js +9 -0
  20. package/src/core/math/isPowerOrTwo.js +5 -0
  21. package/src/core/math/newton_solver_1d.js +1 -1
  22. package/src/core/math/newton_solver_1d.spec.js +9 -0
  23. package/src/core/math/pingpong.spec.js +11 -0
  24. package/src/core/math/random/randomBytes.js +16 -0
  25. package/src/core/math/random/randomFloatBetween.spec.js +8 -0
  26. package/src/core/math/random/randomFromArray.js +3 -3
  27. package/src/core/math/random/randomIntegerBetween.js +5 -0
  28. package/src/core/math/random/randomIntegerBetween.spec.js +7 -0
  29. package/src/core/math/statistics/halton_sequence.spec.js +17 -0
  30. package/src/engine/asset/AssetManager.d.ts +11 -1
  31. package/src/engine/asset/AssetManager.spec.js +2 -2
  32. package/src/engine/control/ControlContext.js +2 -1
  33. package/src/engine/ecs/EntityBuilder.d.ts +6 -0
  34. package/src/engine/ecs/EntityBuilder.js +2 -22
  35. package/src/engine/ecs/EntityBuilder.spec.js +71 -1
  36. package/src/engine/ecs/EntityBuilderFlags.js +20 -0
  37. package/src/engine/ecs/EntityComponentDataset.js +3 -6
  38. package/src/engine/ecs/dynamic_actions/DynamicActorSystem.js +2 -1
  39. package/src/engine/ecs/gui/menu/radial/RadialContextMenu.js +2 -1
  40. package/src/engine/ecs/guid/GUID.js +48 -26
  41. package/src/engine/ecs/guid/GUID.spec.js +56 -10
  42. package/src/engine/ecs/speaker/VoiceSystem.js +2 -1
  43. package/src/engine/ecs/transform/Transform.d.ts +11 -1
  44. package/src/engine/ecs/transform/Transform.js +6 -3
  45. package/src/engine/ecs/transform/Transform.spec.js +67 -1
  46. package/src/engine/graphics/ecs/decal/v2/prototypeDecalSystem.js +2 -1
  47. package/src/engine/physics/fluid/Fluid.js +3 -0
  48. /package/src/core/geom/{Matrix3.js → m3_determinant.js} +0 -0
@@ -1,3 +1,5 @@
1
+ import { assert } from "../../assert.js";
2
+
1
3
  /**
2
4
  * Inclusive random between two boundaries, result is integer
3
5
  * @param {function} random
@@ -6,6 +8,9 @@
6
8
  * @returns {number}
7
9
  */
8
10
  export function randomIntegerBetween(random, min, max) {
11
+ assert.isInteger(min, 'min');
12
+ assert.isInteger(max, 'max');
13
+
9
14
  const span = max - min;
10
15
 
11
16
  const roll = random();
@@ -0,0 +1,7 @@
1
+ import { randomIntegerBetween } from "./randomIntegerBetween.js";
2
+ import { returnOne, returnZero } from "../../function/Functions.js";
3
+
4
+ test("limits", () => {
5
+ expect(randomIntegerBetween(returnZero, -3, 7)).toEqual(-3);
6
+ expect(randomIntegerBetween(returnOne, -3, 7)).toEqual(7);
7
+ });
@@ -0,0 +1,17 @@
1
+ import { halton_sequence } from "./halton_sequence.js";
2
+
3
+ test("unique values in base 10", () => {
4
+
5
+ const values = [];
6
+
7
+ for (let i = 0; i < 10; i++) {
8
+ values.push(halton_sequence(10, i));
9
+ }
10
+
11
+ values.sort();
12
+
13
+ for (let i = 1; i < 10; i++) {
14
+ expect(values[i]).not.toEqual(values[i - 1]);
15
+ }
16
+
17
+ });
@@ -13,6 +13,14 @@ interface AssetManagerOptions<CTX> {
13
13
  executor?: ConcurrentExecutor
14
14
  }
15
15
 
16
+ interface GetOptions<T> {
17
+ type: string
18
+ path: string
19
+ callback: (asset: Asset<T>) => any
20
+ failure: (reason: any) => any
21
+ progress: (current: number, total: number) => any
22
+ }
23
+
16
24
  export declare class AssetManager<CTX> {
17
25
  constructor(options?: AssetManagerOptions<CTX>)
18
26
 
@@ -24,13 +32,15 @@ export declare class AssetManager<CTX> {
24
32
 
25
33
  shutdown(immediate?: boolean): Promise<void>
26
34
 
35
+ get<T>(options: GetOptions<T>): void
36
+
27
37
  promise<T>(path: string, type: string, options?: PromiseOptions): Promise<Asset<T>>
28
38
 
29
39
  remove(path: string, type: string): boolean
30
40
 
31
41
  clear(): void
32
42
 
33
- registerLoader<T>(type: string, loader: AssetLoader<T, CTX>): Promise<AssetLoader<T,CTX>>
43
+ registerLoader<T>(type: string, loader: AssetLoader<T, CTX>): Promise<AssetLoader<T, CTX>>
34
44
 
35
45
  unregisterLoader(type: string): Promise<void>
36
46
 
@@ -16,7 +16,7 @@ function dummyEngine() {
16
16
  }
17
17
 
18
18
  class DummyLoader extends AssetLoader {
19
- load(scope,path, success, failure, progress) {
19
+ load(scope, path, success, failure, progress) {
20
20
  success(new Asset(() => 1));
21
21
  }
22
22
  }
@@ -29,7 +29,7 @@ test('successful get', async () => {
29
29
  am.startup();
30
30
 
31
31
  return new Promise(function (resolve, reject) {
32
- am.get('bla', 'a', resolve, reject);
32
+ am.get({ path: 'bla', type: 'a', callback: resolve, failure: reject });
33
33
  });
34
34
  });
35
35
 
@@ -1,7 +1,8 @@
1
- import EntityBuilder, { EntityBuilderFlags } from "../ecs/EntityBuilder.js";
1
+ import EntityBuilder from "../ecs/EntityBuilder.js";
2
2
  import { ControlContextState } from "./ControlContextState.js";
3
3
  import { IllegalStateException } from "../../core/fsm/exceptions/IllegalStateException.js";
4
4
  import { SerializationMetadata } from "../ecs/components/SerializationMetadata.js";
5
+ import { EntityBuilderFlags } from "../ecs/EntityBuilderFlags.js";
5
6
 
6
7
  export class ControlContext {
7
8
  constructor() {
@@ -11,6 +11,8 @@ export default class EntityBuilder {
11
11
 
12
12
  removeComponent<T>(componentType: Type<T>): T | null
13
13
 
14
+ removeAllComponents(): void
15
+
14
16
  getComponent<T>(componentType: Type<T>): T | null
15
17
 
16
18
  getComponentSafe<T>(componentType: Type<T>): T
@@ -30,4 +32,8 @@ export default class EntityBuilder {
30
32
  removeEventListener(eventName: string, listener: (data?: any) => void, context?: any): EntityBuilder
31
33
 
32
34
  static readFromDataset(entity: number, dataset: EntityComponentDataset): EntityBuilder
35
+
36
+ getFlag(flag: number): boolean
37
+
38
+ setFlag(flag: number, value: number): void
33
39
  }
@@ -2,27 +2,7 @@ import Signal from "../../core/events/signal/Signal.js";
2
2
  import { assert } from "../../core/assert.js";
3
3
  import { EventType } from "./EntityManager.js";
4
4
  import { isDefined } from "../../core/process/matcher/Matchers.js";
5
-
6
- /**
7
- *
8
- * @enum
9
- */
10
- export const EntityBuilderFlags = {
11
- /**
12
- * Whether the entity is built, set internally
13
- */
14
- Built: 1,
15
- /**
16
- * If component type is not registered on the {@link EntityComponentDataset} when calling {@link #build} - will register the component first
17
- */
18
- RegisterComponents: 2,
19
- /**
20
- * Entity builder will watch destruction of the entity (subscribe to event), this will make the EntityBuilder automatically
21
- * recognize when the corresponding entity is destroyed outside the EntityBuilder API
22
- * NOTE: useful to turn off to save a bit of memory, as those event listeners take up a bit of space. Feel free to turn this flag off when you don't care to keep the reference to the EntityBuilder
23
- */
24
- WatchDestruction: 4
25
- };
5
+ import { EntityBuilderFlags } from "./EntityBuilderFlags.js";
26
6
 
27
7
  /**
28
8
  * Set of default flags
@@ -152,7 +132,7 @@ class EntityBuilder {
152
132
  */
153
133
  add(componentInstance) {
154
134
  if (componentInstance === undefined) {
155
- throw new Error("Can not add " + componentInstance + " to EntityBuilder");
135
+ throw new Error(`Can not add ${componentInstance} to EntityBuilder`);
156
136
  }
157
137
 
158
138
  assert.notOk(this.hasComponent(Object.getPrototypeOf(componentInstance).constructor), 'Component of this type already exists');
@@ -1,5 +1,6 @@
1
- import EntityBuilder, { EntityBuilderFlags } from "./EntityBuilder.js";
1
+ import EntityBuilder from "./EntityBuilder.js";
2
2
  import { EntityComponentDataset } from "./EntityComponentDataset.js";
3
+ import { EntityBuilderFlags } from "./EntityBuilderFlags.js";
3
4
 
4
5
 
5
6
  class DummyComponent {
@@ -62,3 +63,72 @@ test("'Built' flag is reset when entity is removed without invoking 'destroy' me
62
63
 
63
64
  expect(b.getFlag(EntityBuilderFlags.Built)).toBe(false);
64
65
  });
66
+
67
+ test("removeAllComponents from empty", () => {
68
+ const entity = new EntityBuilder();
69
+
70
+ expect(() => entity.removeAllComponents()).not.toThrow()
71
+ });
72
+
73
+ test("removeAllComponents with 1 entity", () => {
74
+ const entity = new EntityBuilder();
75
+
76
+ entity.add(new DummyComponent());
77
+
78
+ expect(entity.hasComponent(DummyComponent)).toBe(true);
79
+
80
+ entity.removeAllComponents();
81
+
82
+ expect(entity.hasComponent(DummyComponent)).toBe(false);
83
+ });
84
+
85
+ test("removeComponent when component is not preset", () => {
86
+ const entity = new EntityBuilder();
87
+
88
+ expect(entity.removeComponent(DummyComponent)).toBe(null);
89
+ });
90
+
91
+ test("removeComponent when component is preset", () => {
92
+ const entity = new EntityBuilder();
93
+
94
+ const component = new DummyComponent();
95
+
96
+ entity.add(component)
97
+
98
+ expect(entity.removeComponent(DummyComponent)).toBe(component);
99
+
100
+ expect(entity.hasComponent(DummyComponent)).toBe(false);
101
+ });
102
+
103
+ test("getComponentSafe throws when component is missing", () => {
104
+
105
+ const entity = new EntityBuilder();
106
+
107
+ expect(() => entity.getComponentSafe(DummyComponent)).toThrow();
108
+
109
+ });
110
+ test("getComponentSafe throws when component is present", () => {
111
+
112
+ const entity = new EntityBuilder();
113
+
114
+ const component = new DummyComponent();
115
+ entity.add(component);
116
+
117
+ expect(() => entity.getComponentSafe(DummyComponent)).not.toThrow();
118
+
119
+ expect(entity.getComponentSafe(DummyComponent)).toBe(component);
120
+ });
121
+
122
+ test("adding component to live entity results in component being added to the dataset", () => {
123
+
124
+ const entity = new EntityBuilder();
125
+
126
+ const ecd = sampleDataset();
127
+
128
+ entity.build(ecd)
129
+
130
+ const component = new DummyComponent();
131
+ entity.add(component);
132
+
133
+ expect(ecd.getComponent(entity.entity, DummyComponent)).toBe(component);
134
+ });
@@ -0,0 +1,20 @@
1
+ /**
2
+ *
3
+ * @enum
4
+ */
5
+ export const EntityBuilderFlags = {
6
+ /**
7
+ * Whether the entity is built, set internally
8
+ */
9
+ Built: 1,
10
+ /**
11
+ * If component type is not registered on the {@link EntityComponentDataset} when calling {@link #build} - will register the component first
12
+ */
13
+ RegisterComponents: 2,
14
+ /**
15
+ * Entity builder will watch destruction of the entity (subscribe to event), this will make the EntityBuilder automatically
16
+ * recognize when the corresponding entity is destroyed outside the EntityBuilder API
17
+ * NOTE: useful to turn off to save a bit of memory, as those event listeners take up a bit of space. Feel free to turn this flag off when you don't care to keep the reference to the EntityBuilder
18
+ */
19
+ WatchDestruction: 4
20
+ };
@@ -1071,7 +1071,7 @@ export class EntityComponentDataset {
1071
1071
  * @param {function} callback
1072
1072
  * @param {*} [thisArg]
1073
1073
  */
1074
- getComponentAsync (entityId, componentClass, callback, thisArg) {
1074
+ getComponentAsync(entityId, componentClass, callback, thisArg) {
1075
1075
  const component = this.getComponent(entityId, componentClass);
1076
1076
 
1077
1077
  const handler = (options) => {
@@ -1274,11 +1274,8 @@ export class EntityComponentDataset {
1274
1274
  */
1275
1275
  traverseComponentsByIndex(componentTypeIndex, visitor, thisArg) {
1276
1276
 
1277
- if (!ENV_PRODUCTION) {
1278
- assert.isNumber(componentTypeIndex, "componentTypeIndex");
1279
- assert.isFunction(visitor, "visitor");
1280
- }
1281
-
1277
+ assert.isNumber(componentTypeIndex, "componentTypeIndex");
1278
+ assert.isFunction(visitor, "visitor");
1282
1279
 
1283
1280
  this.__traverseComponentsByIndex_via_property(componentTypeIndex, visitor, thisArg);
1284
1281
  }
@@ -5,7 +5,7 @@ import { DataScope } from "../../../../../model/game/unit/actions/data/DataScope
5
5
  import { Blackboard } from "../../intelligence/blackboard/Blackboard.js";
6
6
  import { compareNumbersDescending, returnTrue } from "../../../core/function/Functions.js";
7
7
  import { EntityProxyScope } from "../binding/EntityProxyScope.js";
8
- import EntityBuilder, { EntityBuilderFlags } from "../EntityBuilder.js";
8
+ import EntityBuilder from "../EntityBuilder.js";
9
9
  import { BehaviorComponent } from "../../intelligence/behavior/ecs/BehaviorComponent.js";
10
10
  import { SequenceBehavior } from "../../intelligence/behavior/composite/SequenceBehavior.js";
11
11
  import { DieBehavior } from "../../intelligence/behavior/ecs/DieBehavior.js";
@@ -22,6 +22,7 @@ import { randomFloatBetween } from "../../../core/math/random/randomFloatBetween
22
22
  import { randomMultipleFromArray } from "../../../core/collection/array/randomMultipleFromArray.js";
23
23
  import { ResourceAccessSpecification } from "../../../core/model/ResourceAccessSpecification.js";
24
24
  import { ResourceAccessKind } from "../../../core/model/ResourceAccessKind.js";
25
+ import { EntityBuilderFlags } from "../EntityBuilderFlags.js";
25
26
 
26
27
  /**
27
28
  * In seconds
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import { SerializationMetadata } from "../../../components/SerializationMetadata.js";
5
5
 
6
- import EntityBuilder, { EntityBuilderFlags } from "../../../EntityBuilder.js";
6
+ import EntityBuilder from "../../../EntityBuilder.js";
7
7
  import GUIElement from "../../GUIElement.js";
8
8
  import { MouseEvents } from "../../../../input/devices/events/MouseEvents.js";
9
9
  import { TouchEvents } from "../../../../input/devices/events/TouchEvents.js";
@@ -12,6 +12,7 @@ import RadialMenuView from "../../../../../view/elements/radial/RadialMenu.js";
12
12
  import { animateAppearance } from "./AnimateAppearance.js";
13
13
  import { animateDisappearance } from "./AnimateDisappearance.js";
14
14
  import { RadialMenuSettings } from "./RadialMenuSettings.js";
15
+ import { EntityBuilderFlags } from "../../../EntityBuilderFlags.js";
15
16
 
16
17
  /**
17
18
  *
@@ -1,8 +1,9 @@
1
1
  import { seededRandom } from "../../../core/math/random/seededRandom.js";
2
2
  import { randomUint8 } from "../../../core/math/random/randomUint8.js";
3
- import { is_typed_array_equals } from "../../../core/collection/array/typed/is_typed_array_equals.js";
4
3
  import { dec2hex } from "../../../core/binary/dec2hex.js";
5
4
  import { array_copy } from "../../../core/collection/array/copyArray.js";
5
+ import { randomBytes } from "../../../core/math/random/randomBytes.js";
6
+ import { assert } from "../../../core/assert.js";
6
7
 
7
8
  // Previous uuid creation time
8
9
  let _lastMSecs = 0;
@@ -10,23 +11,8 @@ let _lastNSecs = 0;
10
11
 
11
12
  const random = seededRandom(Date.now());
12
13
 
13
- /**
14
- *
15
- * @param {Uint8Array} result
16
- * @param {number} result_offset
17
- * @param {function():number} random
18
- * @param {number} count
19
- */
20
- function randomBytes(result, result_offset, random, count) {
21
- for (let i = 0; i < count; i++) {
22
-
23
- result[result_offset + i] = randomUint8(random);
24
-
25
- }
26
- }
27
-
28
14
  // node and clockseq need to be initialized to random values.
29
- let _nodeId = new Uint8Array(6);
15
+ const _nodeId = new Uint8Array(6);
30
16
 
31
17
  // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1)
32
18
  randomBytes(_nodeId, 0, random, 6);
@@ -41,15 +27,14 @@ let _clockseq = ((randomUint8(random) << 8) | randomUint8(random)) & 0x3fff;
41
27
  export class GUID {
42
28
  #data = new Uint8Array(16);
43
29
 
44
- constructor() {
45
- this.v1();
46
- }
47
-
48
30
  /**
49
31
  *
50
32
  * @param {number[]|Uint8Array|ArrayLike<number>} bytes
51
33
  */
52
34
  set data(bytes) {
35
+ assert.isArrayLike(bytes, 'bytes');
36
+ assert.greaterThanOrEqual(bytes.length, 16, 'bytes.length >= 16');
37
+
53
38
  array_copy(bytes, 0, this.#data, 0, 16);
54
39
  }
55
40
 
@@ -136,12 +121,27 @@ export class GUID {
136
121
  }
137
122
  }
138
123
 
124
+ /**
125
+ *
126
+ * @return {GUID}
127
+ */
128
+ static v1() {
129
+ const uuid = new GUID();
130
+
131
+ uuid.v1();
132
+
133
+ return uuid;
134
+ }
135
+
139
136
  /***
140
137
  * String in UUID format
141
138
  * @see https://github.com/uuidjs/uuid/blob/8f028c4ea42ce41a9a9dc5fa634abe525b2e2066/src/parse.js#L3
142
139
  * @param {string} string
143
140
  */
144
141
  parse(string) {
142
+ assert.isString(string, 'string');
143
+ assert.greaterThanOrEqual(string.length, 36, 'string.length');
144
+
145
145
  let v;
146
146
  const arr = this.#data;
147
147
 
@@ -173,6 +173,19 @@ export class GUID {
173
173
  arr[15] = v & 0xff;
174
174
  }
175
175
 
176
+ /**
177
+ *
178
+ * @param {string} string
179
+ * @return {GUID}
180
+ */
181
+ static parse(string) {
182
+ const r = new GUID();
183
+
184
+ r.parse(string);
185
+
186
+ return r;
187
+ }
188
+
176
189
  /**
177
190
  * @see https://github.com/uuidjs/uuid/blob/8f028c4ea42ce41a9a9dc5fa634abe525b2e2066/src/stringify.js#L16
178
191
  * @returns {string}
@@ -218,7 +231,16 @@ export class GUID {
218
231
  * @returns {boolean}
219
232
  */
220
233
  equals(other) {
221
- return is_typed_array_equals(this.#data, other.#data);
234
+ const this_data = this.#data;
235
+ const other_data = other.#data;
236
+
237
+ for (let i = 0; i < 16; i++) {
238
+ if (this_data[i] !== other_data[i]) {
239
+ return false;
240
+ }
241
+ }
242
+
243
+ return true;
222
244
  }
223
245
 
224
246
  /**
@@ -228,10 +250,10 @@ export class GUID {
228
250
  const data = this.#data;
229
251
 
230
252
  // use some non-metadata bytes as a hash
231
- return data[0]
232
- | data[1] << 8
233
- | data[2] << 16
234
- | data[3] << 24
253
+ return data[3] // low byte of "time_low", very likely to differ between two UUIDs
254
+ | data[5] << 8 // low byte of "time_mid"
255
+ | data[9] << 16 // "clock_seq_low"
256
+ | data[15] << 24 // low byte of "node"
235
257
  ;
236
258
  }
237
259
 
@@ -1,19 +1,15 @@
1
1
  import { GUID } from "./GUID.js";
2
2
 
3
3
  test("uniqueness out of 2", () => {
4
- const a = new GUID();
5
- const b = new GUID();
4
+ const a = GUID.v1();
5
+ const b = GUID.v1();
6
6
 
7
7
  expect(a.equals(b)).toBe(false);
8
8
  });
9
9
 
10
-
11
10
  test("equality", () => {
12
- const a = new GUID();
13
- const b = new GUID();
14
-
15
- a.parse("a88bb73a-c89f-11ed-afa1-0242ac120002");
16
- b.parse("a88bb73a-c89f-11ed-afa1-0242ac120002");
11
+ const a = GUID.parse("a88bb73a-c89f-11ed-afa1-0242ac120002");
12
+ const b = GUID.parse("a88bb73a-c89f-11ed-afa1-0242ac120002");
17
13
 
18
14
  expect(a.equals(b)).toBe(true);
19
15
 
@@ -28,10 +24,24 @@ test("hash stability", () => {
28
24
  expect(guid.hash()).toBe(guid.hash());
29
25
  });
30
26
 
27
+ test("copy", () => {
28
+ const a = GUID.parse("a88bb73a-c89f-11ed-afa1-0242ac120002");
29
+ const a_string = a.toString();
30
+
31
+ const b = GUID.parse("bb75b300-c89f-11ed-afa1-0242ac120002");
32
+
33
+ expect(a.equals(b)).toBe(false);
34
+
35
+ b.copy(a);
36
+
37
+ expect(a.equals(b)).toBe(true);
38
+
39
+ // make sure that "a" is not changed
40
+ expect(a.toString()).toEqual(a_string);
41
+ });
31
42
 
32
43
  test("to/from JSON consistency", () => {
33
- const a = new GUID();
34
- a.parse("bb75b300-c89f-11ed-afa1-0242ac120002");
44
+ const a = GUID.parse("bb75b300-c89f-11ed-afa1-0242ac120002");
35
45
 
36
46
  const b = new GUID();
37
47
 
@@ -39,3 +49,39 @@ test("to/from JSON consistency", () => {
39
49
 
40
50
  expect(b.equals(a)).toBe(true)
41
51
  });
52
+
53
+ test(".data setter performs a copy instead of assignment", () => {
54
+ const id = new GUID();
55
+
56
+ const data = new Uint8Array(16);
57
+
58
+ id.data = data;
59
+
60
+ expect(id.data).not.toBe(data);
61
+ });
62
+
63
+ test(".data set/get", () => {
64
+ const a = new GUID();
65
+
66
+ const sample_0 = [
67
+ 0xFF, 0xFF, 0xFF, 0xFF,
68
+ 0xFF, 0xFF, 0xFF, 0xFF,
69
+ 0xFF, 0xFF, 0xFF, 0xFF,
70
+ 0xFF, 0xFF, 0xFF, 0xFF,
71
+ ];
72
+
73
+ a.data = sample_0;
74
+
75
+ expect(Array.from(a.data)).toEqual(sample_0);
76
+
77
+ const sample_1 = [
78
+ 0x00, 0x01, 0x02, 0x03,
79
+ 0x04, 0x05, 0x06, 0x07,
80
+ 0x08, 0x09, 0x0A, 0x0B,
81
+ 0x0C, 0x0D, 0x0E, 0x0F,
82
+ ];
83
+
84
+ a.data = sample_1;
85
+
86
+ expect(Array.from(a.data)).toEqual(sample_1);
87
+ });
@@ -1,6 +1,6 @@
1
1
  import { max2 } from "../../../core/math/max2.js";
2
2
  import { Voice } from "./Voice.js";
3
- import EntityBuilder, { EntityBuilderFlags } from "../EntityBuilder.js";
3
+ import EntityBuilder from "../EntityBuilder.js";
4
4
  import GUIElement from "../gui/GUIElement.js";
5
5
  import { SerializationMetadata } from "../components/SerializationMetadata.js";
6
6
  import HeadsUpDisplay from "../gui/hud/HeadsUpDisplay.js";
@@ -32,6 +32,7 @@ import { globalMetrics } from "../../metrics/GlobalMetrics.js";
32
32
  import { MetricsCategory } from "../../metrics/MetricsCategory.js";
33
33
  import { ResourceAccessSpecification } from "../../../core/model/ResourceAccessSpecification.js";
34
34
  import { ResourceAccessKind } from "../../../core/model/ResourceAccessKind.js";
35
+ import { EntityBuilderFlags } from "../EntityBuilderFlags.js";
35
36
 
36
37
  /**
37
38
  * Delay before the user notices the text and begins to read
@@ -6,7 +6,7 @@ export class Transform {
6
6
  public readonly rotation: Quaternion
7
7
  public readonly scale: Vector3
8
8
 
9
- public readonly matrix:ArrayLike<number>
9
+ public readonly matrix: ArrayLike<number>
10
10
 
11
11
  public lookAt(target: Vector3): void
12
12
 
@@ -22,6 +22,8 @@ export class Transform {
22
22
  rotation?: { x: number, y: number, z: number, w: number },
23
23
  }): void
24
24
 
25
+ toJSON(): any
26
+
25
27
  copy(other: Transform): void
26
28
 
27
29
  clone(): Transform
@@ -37,4 +39,12 @@ export class Transform {
37
39
  multiplyTransforms(a: Transform, b: Transform): void
38
40
 
39
41
  makeIdentity(): void
42
+
43
+ setFlag(flag: number): void
44
+
45
+ getFlag(flag: number): boolean
46
+
47
+ clearFlag(flag: number): void
48
+
49
+ writeFlag(flag: number, value: boolean): void
40
50
  }
@@ -10,6 +10,7 @@ import { TransformFlags } from "./TransformFlags.js";
10
10
  import { allocate_transform_m4 } from "../../graphics/ecs/mesh-v2/allocate_transform_m4.js";
11
11
  import { assert } from "../../../core/assert.js";
12
12
  import { m4_multiply } from "../../../core/geom/3d/matrix/m4_multiply.js";
13
+ import { MATRIX_4_IDENTITY } from "../../../core/geom/3d/matrix/MATRIX_4_IDENTITY.js";
13
14
 
14
15
  /**
15
16
  *
@@ -315,9 +316,11 @@ export class Transform {
315
316
  * - scale: [1,1,1]
316
317
  */
317
318
  makeIdentity() {
318
- this.position.copy(Vector3.zero);
319
- this.rotation.copy(Quaternion.identity);
320
- this.scale.copy(Vector3.one);
319
+ this.fromMatrix4(MATRIX_4_IDENTITY);
320
+ }
321
+
322
+ toString() {
323
+ return `{ position: ${this.position}, rotation: ${this.rotation}, scale: ${this.scale} }`;
321
324
  }
322
325
  }
323
326