@woosh/meep-engine 2.48.17 → 2.48.18

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 (43) 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/Quaternion.js +4 -0
  13. package/src/core/geom/Vector3.js +9 -31
  14. package/src/core/math/fract.spec.js +11 -0
  15. package/src/core/math/isPowerOfTwo.spec.js +9 -0
  16. package/src/core/math/isPowerOrTwo.js +5 -0
  17. package/src/core/math/newton_solver_1d.js +1 -1
  18. package/src/core/math/newton_solver_1d.spec.js +9 -0
  19. package/src/core/math/pingpong.spec.js +11 -0
  20. package/src/core/math/random/randomBytes.js +16 -0
  21. package/src/core/math/random/randomFloatBetween.spec.js +8 -0
  22. package/src/core/math/random/randomFromArray.js +3 -3
  23. package/src/core/math/random/randomIntegerBetween.js +5 -0
  24. package/src/core/math/random/randomIntegerBetween.spec.js +7 -0
  25. package/src/core/math/statistics/halton_sequence.spec.js +17 -0
  26. package/src/engine/asset/AssetManager.d.ts +11 -1
  27. package/src/engine/asset/AssetManager.spec.js +2 -2
  28. package/src/engine/control/ControlContext.js +2 -1
  29. package/src/engine/ecs/EntityBuilder.d.ts +6 -0
  30. package/src/engine/ecs/EntityBuilder.js +2 -22
  31. package/src/engine/ecs/EntityBuilder.spec.js +71 -1
  32. package/src/engine/ecs/EntityBuilderFlags.js +20 -0
  33. package/src/engine/ecs/EntityComponentDataset.js +3 -6
  34. package/src/engine/ecs/dynamic_actions/DynamicActorSystem.js +2 -1
  35. package/src/engine/ecs/gui/menu/radial/RadialContextMenu.js +2 -1
  36. package/src/engine/ecs/guid/GUID.js +48 -26
  37. package/src/engine/ecs/guid/GUID.spec.js +56 -10
  38. package/src/engine/ecs/speaker/VoiceSystem.js +2 -1
  39. package/src/engine/ecs/transform/Transform.d.ts +11 -1
  40. package/src/engine/ecs/transform/Transform.js +6 -3
  41. package/src/engine/ecs/transform/Transform.spec.js +67 -1
  42. package/src/engine/graphics/ecs/decal/v2/prototypeDecalSystem.js +2 -1
  43. package/src/engine/physics/fluid/Fluid.js +3 -0
@@ -38,7 +38,7 @@ class Vector3 {
38
38
  * @param {number[]} array
39
39
  * @param {number} offset
40
40
  */
41
- readFromArray(array, offset=0) {
41
+ readFromArray(array, offset = 0) {
42
42
  this.set(
43
43
  array[offset],
44
44
  array[offset + 1],
@@ -51,16 +51,16 @@ class Vector3 {
51
51
  * @param {number[]} array
52
52
  * @param {number} offset
53
53
  */
54
- writeToArray(array, offset=0) {
54
+ writeToArray(array, offset = 0) {
55
55
  array[offset] = this.x;
56
56
  array[offset + 1] = this.y;
57
57
  array[offset + 2] = this.z;
58
58
  }
59
59
 
60
- asArray(){
60
+ asArray() {
61
61
  const r = [];
62
62
 
63
- this.writeToArray(r,0);
63
+ this.writeToArray(r, 0);
64
64
 
65
65
  return r;
66
66
  }
@@ -171,12 +171,12 @@ class Vector3 {
171
171
  * @param {Vector3} a
172
172
  * @param {Vector3} b
173
173
  */
174
- addVectors(a,b){
174
+ addVectors(a, b) {
175
175
  const x = a.x + b.x;
176
176
  const y = a.y + b.y;
177
177
  const z = a.z + b.z;
178
178
 
179
- this.set(x,y,z);
179
+ this.set(x, y, z);
180
180
  }
181
181
 
182
182
  /**
@@ -378,7 +378,7 @@ class Vector3 {
378
378
  * @returns {number}
379
379
  */
380
380
  length() {
381
- return v3Length(this);
381
+ return v3_length(this.x, this.y, this.z);
382
382
  }
383
383
 
384
384
  /**
@@ -532,7 +532,7 @@ class Vector3 {
532
532
  * @param {number} fraction
533
533
  */
534
534
  lerpVectors(a, b, fraction) {
535
- v3Lerp(this, a, b, fraction);
535
+ v3_lerp(this, a.x, a.y, a.z, b.x, b.y, b.z, fraction);
536
536
  }
537
537
 
538
538
  /**
@@ -806,7 +806,7 @@ class Vector3 {
806
806
  }
807
807
 
808
808
  toString() {
809
- return `[x:${this.x}, y:${this.y}, z:${this.z}]`;
809
+ return `{ x:${this.x}, y:${this.y}, z:${this.z} }`;
810
810
  }
811
811
 
812
812
  /**
@@ -1095,7 +1095,6 @@ Vector3.back = Object.freeze(new Vector3(0, 0, -1));
1095
1095
 
1096
1096
  Vector3.typeName = "Vector3";
1097
1097
 
1098
-
1099
1098
  /**
1100
1099
  *
1101
1100
  * @param {number} x0
@@ -1109,25 +1108,4 @@ Vector3.typeName = "Vector3";
1109
1108
  Vector3._dot = v3_dot;
1110
1109
 
1111
1110
 
1112
- /**
1113
- *
1114
- * @param {{x:number, y:number, z:number}} v
1115
- * @return {number}
1116
- */
1117
- function v3Length(v) {
1118
- return v3_length(v.x, v.y, v.z);
1119
- }
1120
-
1121
-
1122
- /**
1123
- *
1124
- * @param {Vector3} result
1125
- * @param {Vector3} a
1126
- * @param {Vector3} b
1127
- * @param {number} fraction
1128
- */
1129
- function v3Lerp(result, a, b, fraction) {
1130
- v3_lerp(result, a.x, a.y, a.z, b.x, b.y, b.z, fraction);
1131
- }
1132
-
1133
1111
  export default Vector3;
@@ -0,0 +1,11 @@
1
+ import { fract } from "./fract.js";
2
+
3
+ test("correctness", () => {
4
+
5
+ expect(fract(0)).toBeCloseTo(0);
6
+ expect(fract(0.1)).toBeCloseTo(0.1);
7
+ expect(fract(-0.1)).toBeCloseTo(-0.1);
8
+ expect(fract(1.1)).toBeCloseTo(0.1);
9
+ expect(fract(-1.1)).toBeCloseTo(-0.1);
10
+
11
+ });
@@ -0,0 +1,9 @@
1
+ import { isPowerOfTwo } from "./isPowerOrTwo.js";
2
+
3
+ test("correctness", () => {
4
+ expect(isPowerOfTwo(1)).toBe(true);
5
+ expect(isPowerOfTwo(2)).toBe(true);
6
+ expect(isPowerOfTwo(3)).toBe(false);
7
+ expect(isPowerOfTwo(4)).toBe(true);
8
+ expect(isPowerOfTwo(5)).toBe(false);
9
+ });
@@ -1,10 +1,15 @@
1
+ import { assert } from "../assert.js";
2
+
1
3
  /**
2
4
  * Is the number a power of two?
3
5
  * e.g. 2,4,8,16 etc.
6
+ * NOTE: only valid for non-negative integers
4
7
  * @param {number} value
5
8
  * @returns {boolean}
6
9
  */
7
10
  export function isPowerOfTwo(value) {
11
+ assert.isNonNegativeInteger(value, 'value');
12
+
8
13
 
9
14
  return (value & (value - 1)) === 0 && value !== 0;
10
15
 
@@ -2,7 +2,7 @@
2
2
  * Newtonian solver, works by moving along the curve in the direction of gradient
3
3
  * @template T
4
4
  * @param {function(T):number} f
5
- * @param {T} xStart
5
+ * @param {number} xStart
6
6
  * @param {number} [max_steps]
7
7
  * @param {number} [eps]
8
8
  * @returns {number}
@@ -0,0 +1,9 @@
1
+ import { newton_solver_1d } from "./newton_solver_1d.js";
2
+
3
+ test("solve for line", () => {
4
+ expect(newton_solver_1d((x) => x * 2 + 5, 1))
5
+ .toBeCloseTo(-2.5);
6
+
7
+ expect(newton_solver_1d((x) => -x * 7 - 3, 1))
8
+ .toBeCloseTo(-0.429);
9
+ });
@@ -0,0 +1,11 @@
1
+ import { pingpong } from "./pingpong.js";
2
+
3
+ test("correctness", () => {
4
+
5
+ expect(pingpong(0, 1)).toBe(0);
6
+ expect(pingpong(0.1, 1)).toBeCloseTo(0.1);
7
+ expect(pingpong(1, 1)).toBe(1);
8
+ expect(pingpong(1.1, 1)).toBeCloseTo(0.9);
9
+ expect(pingpong(2.1, 1)).toBeCloseTo(0.1);
10
+
11
+ });
@@ -0,0 +1,16 @@
1
+ import { randomUint8 } from "./randomUint8.js";
2
+
3
+ /**
4
+ *
5
+ * @param {Uint8Array} result
6
+ * @param {number} result_offset
7
+ * @param {function():number} random
8
+ * @param {number} count
9
+ */
10
+ export function randomBytes(result, result_offset, random, count) {
11
+ for (let i = 0; i < count; i++) {
12
+
13
+ result[result_offset + i] = randomUint8(random);
14
+
15
+ }
16
+ }
@@ -0,0 +1,8 @@
1
+ import { returnOne, returnZero } from "../../function/Functions.js";
2
+ import { randomFloatBetween } from "./randomFloatBetween.js";
3
+
4
+ test("limits", () => {
5
+
6
+ expect(randomFloatBetween(returnZero, -3.11, 7.23)).toEqual(-3.11);
7
+ expect(randomFloatBetween(returnOne, -3.11, 7.23)).toEqual(7.23);
8
+ })
@@ -1,5 +1,5 @@
1
1
  import { assert } from "../../assert.js";
2
- import { min2 } from "../min2.js";
2
+ import { randomIntegerBetween } from "./randomIntegerBetween.js";
3
3
 
4
4
  /**
5
5
  * @template T
@@ -13,7 +13,7 @@ export function randomFromArray(random, array) {
13
13
 
14
14
  const length = array.length;
15
15
 
16
- const i = min2(length - 1, Math.floor(random() * length));
16
+ const index = randomIntegerBetween(random, 0, length - 1);
17
17
 
18
- return array[i];
18
+ return array[index];
19
19
  }
@@ -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