@woosh/meep-engine 2.62.0 → 2.64.0

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 (54) hide show
  1. package/build/meep.cjs +1061 -1058
  2. package/build/meep.min.js +1 -1
  3. package/build/meep.module.js +1061 -1058
  4. package/package.json +1 -1
  5. package/src/core/binary/EncodingBinaryBuffer.js +7 -43
  6. package/src/core/binary/EncodingBinaryBuffer.spec.js +16 -0
  7. package/src/core/binary/UINT16_MAX.js +5 -0
  8. package/src/core/bvh2/bvh3/EBBVHLeafProxy.js +4 -2
  9. package/src/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.js +5 -5
  10. package/src/core/bvh2/bvh3/query/BVHQueryIntersectsFrustum.js +8 -10
  11. package/src/core/bvh2/bvh3/query/BVHQueryIntersectsRay.js +7 -7
  12. package/src/core/bvh2/bvh3/query/BVHQueryIntersectsSphere.js +37 -0
  13. package/src/core/bvh2/bvh3/query/bvh_query_user_data_generic.js +12 -4
  14. package/src/core/bvh2/bvh3/query/bvh_query_user_data_generic.spec.js +29 -0
  15. package/src/core/cache/LoadingCache.js +4 -1
  16. package/src/core/collection/list/List.js +9 -3
  17. package/src/core/collection/map/BiMap.js +49 -0
  18. package/src/core/geom/3d/aabb/aabb3_from_v3_array.js +11 -4
  19. package/src/core/geom/Vector2.js +6 -4
  20. package/src/engine/ecs/components/Tag.d.ts +2 -0
  21. package/src/engine/ecs/components/Tag.js +19 -28
  22. package/src/engine/ecs/components/Tag.spec.js +47 -0
  23. package/src/engine/ecs/fow/FogOfWar.js +4 -0
  24. package/src/engine/ecs/fow/FogOfWarEditor.js +3 -0
  25. package/src/engine/ecs/terrain/TerrainPreview.js +45 -44
  26. package/src/engine/ecs/terrain/ecs/cling/ClingToTerrain.js +22 -4
  27. package/src/engine/ecs/terrain/tiles/TerrainTile.js +17 -12
  28. package/src/engine/graphics/ecs/mesh/Mesh.d.ts +0 -4
  29. package/src/engine/graphics/ecs/mesh/Mesh.js +0 -11
  30. package/src/engine/graphics/ecs/mesh/MeshSystem.js +57 -67
  31. package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js +49 -86
  32. package/src/engine/graphics/particles/particular/engine/emitter/ParticlePool.js +41 -72
  33. package/src/engine/graphics/particles/particular/engine/emitter/write_particle_patch_uv.js +28 -0
  34. package/src/engine/grid/ORTHOGONAL_NEIGHBOURHOOD_MASK.js +11 -0
  35. package/src/engine/sound/ecs/emitter/SoundEmitterSystem.js +17 -17
  36. package/src/core/binary/stringToByteArray.js +0 -24
  37. package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_sphere.js +0 -81
  38. package/src/engine/ecs/foliage/Foliage.js +0 -151
  39. package/src/engine/ecs/foliage/FoliageLoader.js +0 -39
  40. package/src/engine/ecs/foliage/FoliageVisibilitySetBuilder.js +0 -27
  41. package/src/engine/ecs/foliage/ImpostorFoliage.js +0 -106
  42. package/src/engine/ecs/foliage/InstancedFoliage.js +0 -395
  43. package/src/engine/ecs/foliage/ViewState.js +0 -181
  44. package/src/engine/ecs/foliage/ecs/Foliage2System.js +0 -333
  45. package/src/engine/ecs/foliage/ecs/InstancedMeshComponent.js +0 -70
  46. package/src/engine/ecs/foliage/ecs/InstancedMeshLayer.js +0 -138
  47. package/src/engine/ecs/foliage/ecs/InstancedMeshSerializationAdapter.js +0 -28
  48. package/src/engine/ecs/foliage/ecs/convertInstancedMeshComponents2Entities.js +0 -64
  49. package/src/engine/ecs/foliage/ecs/optimizeIndividualMeshesEntitiesToInstances.js +0 -233
  50. package/src/engine/save/storage/GooglePlayStorage.js +0 -47
  51. package/src/engine/save/storage/JsonStringCodec.js +0 -24
  52. package/src/engine/save/storage/LocalStorage.js +0 -148
  53. package/src/engine/save/storage/MsgPackCodec.js +0 -22
  54. /package/src/engine/sound/ecs/emitter/{SoundEmitter.spec.js → SoundEmitterSerializationAdapter.spec.js} +0 -0
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.62.0",
8
+ "version": "2.64.0",
9
9
  "main": "build/meep.module.js",
10
10
  "module": "build/meep.module.js",
11
11
  "exports": {
@@ -1,58 +1,22 @@
1
+ import { BiMap } from "../collection/map/BiMap.js";
1
2
  import { BinaryBuffer } from "./BinaryBuffer.js";
2
3
 
3
- class Dictionary {
4
- constructor() {
5
- this.forward = new Map();
6
- this.backward = new Map();
7
- }
8
-
9
- /**
10
- *
11
- * @param {*} value
12
- * @param {number} address
13
- */
14
- add(value, address) {
15
- this.forward.set(address, value);
16
- this.backward.set(value, address);
17
- }
18
-
19
- /**
20
- *
21
- * @param {*} value
22
- * @returns {number|undefined}
23
- */
24
- getAddress(value) {
25
- return this.backward.get(value);
26
- }
27
-
28
- /**
29
- *
30
- * @param {number} address
31
- * @returns {*}
32
- */
33
- getValue(address) {
34
- return this.forward.get(address);
35
- }
36
- }
4
+ export class EncodingBinaryBuffer extends BinaryBuffer {
37
5
 
6
+ __dictionary = new BiMap();
38
7
 
39
- export class EncodingBinaryBuffer extends BinaryBuffer {
40
- constructor() {
41
- super();
42
- this.__dictionary = new Dictionary();
43
- }
44
8
 
45
9
  writeUTF8String(value) {
46
- const address = this.__dictionary.getAddress(value);
10
+ const address = this.__dictionary.getKeyByValue(value);
47
11
 
48
12
  if (address === undefined) {
49
13
  this.writeUint8(0); //mark as complete value
50
14
 
51
- const address1 = this.position;
15
+ const current_address = this.position;
52
16
 
53
17
  super.writeUTF8String(value);
54
18
 
55
- this.__dictionary.add(value, address1);
19
+ this.__dictionary.add(value, current_address);
56
20
  } else {
57
21
  //write as reference
58
22
  this.writeUint32LE(1 | (address << 1));
@@ -72,7 +36,7 @@ export class EncodingBinaryBuffer extends BinaryBuffer {
72
36
 
73
37
  const address = header >> 1;
74
38
 
75
- let value = this.__dictionary.getValue(address);
39
+ let value = this.__dictionary.getValueByKey(address);
76
40
 
77
41
  if (value === undefined) {
78
42
  //remember position
@@ -0,0 +1,16 @@
1
+ import { EncodingBinaryBuffer } from "./EncodingBinaryBuffer.js";
2
+
3
+ test("read/write strings", () => {
4
+
5
+ const buffer = new EncodingBinaryBuffer();
6
+
7
+ buffer.writeUTF8String("hello world");
8
+ buffer.writeUTF8String("cat");
9
+ buffer.writeUTF8String("hello world");
10
+
11
+ buffer.position = 0;
12
+
13
+ expect(buffer.readUTF8String()).toEqual("hello world");
14
+ expect(buffer.readUTF8String()).toEqual("cat");
15
+ expect(buffer.readUTF8String()).toEqual("hello world");
16
+ });
@@ -0,0 +1,5 @@
1
+ /**
2
+ * equal to `Math.pow(2,16) - 1`
3
+ * @type {number}
4
+ */
5
+ export const UINT16_MAX = 65535;
@@ -50,8 +50,10 @@ export class EBBVHLeafProxy {
50
50
  unlink() {
51
51
  assert.equal(this.is_linked, true, 'not linked');
52
52
 
53
- this.#tree.remove_leaf(this.#node_id);
54
- this.#tree.release_node(this.#node_id);
53
+ const node_id = this.#node_id;
54
+
55
+ this.#tree.remove_leaf(node_id);
56
+ this.#tree.release_node(node_id);
55
57
 
56
58
  this.#node_id = -1;
57
59
  this.#tree = null;
@@ -1,9 +1,9 @@
1
- import { aabb3_compute_surface_area } from "../../geom/3d/aabb/aabb3_compute_surface_area.js";
2
- import { min2 } from "../../math/min2.js";
3
- import { max2 } from "../../math/max2.js";
4
1
  import { assert } from "../../assert.js";
5
- import { typed_array_copy } from "../../collection/array/typed/typed_array_copy.js";
6
2
  import { array_copy } from "../../collection/array/array_copy.js";
3
+ import { typed_array_copy } from "../../collection/array/typed/typed_array_copy.js";
4
+ import { aabb3_compute_surface_area } from "../../geom/3d/aabb/aabb3_compute_surface_area.js";
5
+ import { max2 } from "../../math/max2.js";
6
+ import { min2 } from "../../math/min2.js";
7
7
 
8
8
  export const COLUMN_PARENT = 6;
9
9
  export const COLUMN_CHILD_1 = 7;
@@ -373,7 +373,7 @@ export class ExplicitBinaryBoundingVolumeHierarchy {
373
373
  /**
374
374
  *
375
375
  * @param {number} id
376
- * @param {number[]} result
376
+ * @param {number[]|Float32Array} result
377
377
  */
378
378
  node_get_aabb(id, result) {
379
379
  assert.isNonNegativeInteger(id, 'id');
@@ -1,18 +1,16 @@
1
- import { BVHQuery } from "./BVHQuery.js";
2
1
  import { aabb3_array_intersects_frustum_array } from "../../../geom/3d/aabb/aabb3_array_intersects_frustum_array.js";
2
+ import { BVHQuery } from "./BVHQuery.js";
3
3
 
4
4
  const scratch_aabb = [];
5
5
 
6
6
  export class BVHQueryIntersectsFrustum extends BVHQuery {
7
- constructor() {
8
- super();
9
-
10
- /**
11
- * Collection of 6 planes: normal_x, normal_y, normal_z, offset
12
- * @type {number[]}
13
- */
14
- this.frustum = [];
15
- }
7
+
8
+ /**
9
+ * Collection of 6 planes: normal_x, normal_y, normal_z, offset
10
+ * @type {number[]}
11
+ */
12
+ frustum = [];
13
+
16
14
 
17
15
  /**
18
16
  *
@@ -1,21 +1,21 @@
1
- import { BVHQuery } from "./BVHQuery.js";
2
1
  import { aabb3_array_intersects_ray_array } from "../../../geom/3d/aabb/aabb3_array_intersects_ray_array.js";
2
+ import { BVHQuery } from "./BVHQuery.js";
3
3
 
4
4
  const scratch_aabb = [];
5
5
 
6
6
  export class BVHQueryIntersectsRay extends BVHQuery {
7
- constructor() {
8
- super();
9
-
10
- this.ray = [];
11
- }
7
+ /**
8
+ *
9
+ * @type {number[]}
10
+ */
11
+ ray = [];
12
12
 
13
13
  /**
14
14
  *
15
15
  * @param {number[]|ArrayLike<number>} ray
16
16
  * @returns {BVHQueryIntersectsRay}
17
17
  */
18
- static from(ray){
18
+ static from(ray) {
19
19
  const r = new BVHQueryIntersectsRay();
20
20
 
21
21
  r.ray = ray;
@@ -0,0 +1,37 @@
1
+ import { aabb3_array_intersects_sphere_array } from "../../../geom/3d/aabb/aabb3_array_intersects_sphere_array.js";
2
+ import { BVHQuery } from "./BVHQuery.js";
3
+
4
+ const scratch_aabb = [];
5
+
6
+ export class BVHQueryIntersectsSphere extends BVHQuery {
7
+
8
+ /**
9
+ *
10
+ * @type {number[]}
11
+ */
12
+ sphere = [];
13
+
14
+ /**
15
+ *
16
+ * @param {number[]|ArrayLike<number>} sphere
17
+ * @returns {BVHQueryIntersectsRay}
18
+ */
19
+ static from(sphere) {
20
+ const r = new BVHQueryIntersectsSphere();
21
+
22
+ r.sphere = sphere;
23
+
24
+ return r;
25
+ }
26
+
27
+ evaluate(node, tree) {
28
+
29
+ tree.node_get_aabb(node, scratch_aabb);
30
+
31
+ // test node against the ray
32
+ return aabb3_array_intersects_sphere_array(
33
+ scratch_aabb,
34
+ this.sphere
35
+ );
36
+ }
37
+ }
@@ -1,5 +1,6 @@
1
- import { NULL_NODE } from "../ExplicitBinaryBoundingVolumeHierarchy.js";
1
+ import { assert } from "../../../assert.js";
2
2
  import { SCRATCH_UINT32_TRAVERSAL_STACK } from "../../../collection/SCRATCH_UINT32_TRAVERSAL_STACK.js";
3
+ import { NULL_NODE } from "../ExplicitBinaryBoundingVolumeHierarchy.js";
3
4
 
4
5
  const stack = SCRATCH_UINT32_TRAVERSAL_STACK;
5
6
 
@@ -15,9 +16,15 @@ const stack = SCRATCH_UINT32_TRAVERSAL_STACK;
15
16
  */
16
17
  export function bvh_query_user_data_generic(
17
18
  result, result_offset,
18
- bvh,root, query
19
+ bvh, root, query
19
20
  ) {
20
21
 
22
+ assert.isArrayLike(result, 'result');
23
+ assert.isNonNegativeInteger(result_offset, 'result_offset');
24
+ assert.defined(bvh, 'bvh');
25
+ assert.isNonNegativeInteger(root, 'root');
26
+ assert.defined(query, 'query');
27
+
21
28
  if (root === NULL_NODE) {
22
29
  return 0;
23
30
  }
@@ -44,13 +51,14 @@ export function bvh_query_user_data_generic(
44
51
  // test node against the query
45
52
  const pass = query.evaluate(node, bvh);
46
53
 
47
- if (!pass) {
54
+ if (pass === false) {
48
55
  continue;
49
56
  }
50
57
 
51
58
  const node_is_leaf = bvh.node_is_leaf(node);
52
59
 
53
- if (!node_is_leaf) {
60
+ if (node_is_leaf === false) {
61
+ // binary-node
54
62
 
55
63
  // read in-order
56
64
  const child1 = bvh.node_get_child1(node);
@@ -0,0 +1,29 @@
1
+ import { ExplicitBinaryBoundingVolumeHierarchy } from "../ExplicitBinaryBoundingVolumeHierarchy.js";
2
+ import { bvh_query_user_data_generic } from "./bvh_query_user_data_generic.js";
3
+ import { BVHQueryAny } from "./BVHQueryAny.js";
4
+
5
+ test("all-accepting query", () => {
6
+ const bvh = new ExplicitBinaryBoundingVolumeHierarchy();
7
+
8
+ const leaf_a = bvh.allocate_node();
9
+ const leaf_b = bvh.allocate_node();
10
+
11
+ bvh.node_set_user_data(leaf_a, 7);
12
+ bvh.node_set_user_data(leaf_b, 13);
13
+
14
+ bvh.insert_leaf(leaf_a);
15
+ bvh.insert_leaf(leaf_b);
16
+
17
+ const result = [];
18
+
19
+ const count = bvh_query_user_data_generic(
20
+ result, 1,
21
+ bvh, bvh.root,
22
+ BVHQueryAny.INSTANCE
23
+ );
24
+
25
+ expect(count).toBe(2);
26
+ expect(result).toContain(7);
27
+ expect(result).toContain(13);
28
+
29
+ });
@@ -1,7 +1,8 @@
1
1
  //
2
2
 
3
- import { Cache } from "./Cache.js";
3
+ import { assert } from "../assert.js";
4
4
  import { current_time_in_seconds } from "../time/current_time_in_seconds.js";
5
+ import { Cache } from "./Cache.js";
5
6
 
6
7
  /**
7
8
  * @template R
@@ -79,6 +80,8 @@ export class LoadingCache {
79
80
  retryFailed = true
80
81
  }) {
81
82
 
83
+ assert.isFunction(load, 'load');
84
+
82
85
  this.#internal = new Cache({
83
86
  maxWeight,
84
87
  keyWeigher,
@@ -6,8 +6,8 @@
6
6
  import { assert } from "../../assert.js";
7
7
  import Signal from "../../events/signal/Signal.js";
8
8
  import { invokeObjectEquals } from "../../model/object/invokeObjectEquals.js";
9
- import { arraySetDiff } from "../array/arraySetDiff.js";
10
9
  import { arrayIndexByEquality } from "../array/arrayIndexByEquality.js";
10
+ import { arraySetDiff } from "../array/arraySetDiff.js";
11
11
 
12
12
 
13
13
  /**
@@ -51,9 +51,12 @@ class List {
51
51
  /**
52
52
  * Retrieve element at a given position in the list
53
53
  * @param {number} index
54
- * @returns {T}
54
+ * @returns {T|undefined}
55
55
  */
56
56
  get(index) {
57
+ assert.isNumber(index, 'index');
58
+ assert.isNonNegativeInteger(index, 'index');
59
+
57
60
  return this.data[index];
58
61
  }
59
62
 
@@ -63,6 +66,9 @@ class List {
63
66
  * @param {T} value
64
67
  */
65
68
  set(index, value) {
69
+ assert.isNumber(index, 'index');
70
+ assert.isNonNegativeInteger(index, 'index');
71
+
66
72
  const oldValue = this.data[index];
67
73
 
68
74
  if (oldValue !== undefined) {
@@ -183,7 +189,7 @@ class List {
183
189
  /**
184
190
  * Replace the data, replacements is performed surgically, meaning that diff is computed and add/remove operations are performed on the set
185
191
  * This method is tailored to work well with visualisation as only elements that's missing from the new set is removed, and only elements that are new to are added
186
- * Conversely, relevant events are dispatched that a visualisation can observe. This results in fewer changes required to the visualisation
192
+ * Conversely, relevant events are dispatched that can observe. This results in fewer changes required to the visualisation
187
193
  * @param {T[]} newOutput
188
194
  */
189
195
  patch(newOutput) {
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Bi-directional map
3
+ * @template K,V
4
+ */
5
+ export class BiMap {
6
+
7
+ /**
8
+ *
9
+ * @type {Map<K, V>}
10
+ */
11
+ forward = new Map();
12
+ /**
13
+ *
14
+ * @type {Map<V, K>}
15
+ */
16
+ backward = new Map();
17
+
18
+
19
+ /**
20
+ *
21
+ * @param {K} key
22
+ * @param {V} value
23
+ */
24
+ add(key, value) {
25
+ this.forward.set(value, key);
26
+ this.backward.set(key, value);
27
+ }
28
+
29
+ /**
30
+ *
31
+ * @param {V} value
32
+ * @returns {K|undefined}
33
+ */
34
+ getKeyByValue(value) {
35
+ return this.backward.get(value);
36
+ }
37
+
38
+ /**
39
+ *
40
+ * @param {K} address
41
+ * @returns {V|undefined}
42
+ */
43
+ getValueByKey(address) {
44
+ return this.forward.get(address);
45
+ }
46
+ }
47
+
48
+ BiMap.prototype.get = BiMap.prototype.getValueByKey;
49
+ BiMap.prototype.set = BiMap.prototype.add;
@@ -1,10 +1,10 @@
1
- import { min2 } from "../../../math/min2.js";
2
- import { max2 } from "../../../math/max2.js";
3
1
  import { assert } from "../../../assert.js";
2
+ import { max2 } from "../../../math/max2.js";
3
+ import { min2 } from "../../../math/min2.js";
4
4
 
5
5
  /**
6
6
  *
7
- * @param {AABB3} result
7
+ * @param {ArrayLike<number>|number[]|Float32Array|AABB3} result
8
8
  * @param {number[]|ArrayLike<number>|Float32Array} input
9
9
  * @param {number} input_length length of the input array
10
10
  */
@@ -33,5 +33,12 @@ export function aabb3_from_v3_array(result, input, input_length) {
33
33
  z1 = max2(z, z1);
34
34
  }
35
35
 
36
- result.setBounds(x0, y0, z0, x1, y1, z1);
36
+ // read out
37
+ result[0] = x0;
38
+ result[1] = y0;
39
+ result[2] = z0;
40
+
41
+ result[3] = x1;
42
+ result[4] = y1;
43
+ result[5] = z1;
37
44
  }
@@ -6,11 +6,12 @@
6
6
  import { assert } from "../assert.js";
7
7
  import Signal from "../events/signal/Signal.js";
8
8
  import { clamp } from "../math/clamp.js";
9
+ import { EPSILON } from "../math/EPSILON.js";
10
+ import { epsilonEquals } from "../math/epsilonEquals.js";
9
11
  import { lerp } from "../math/lerp.js";
10
12
  import { max2 } from "../math/max2.js";
11
13
  import { min2 } from "../math/min2.js";
12
- import { EPSILON } from "../math/EPSILON.js";
13
- import { epsilonEquals } from "../math/epsilonEquals.js";
14
+ import { computeHashFloat } from "../primitives/numbers/computeHashFloat.js";
14
15
 
15
16
  class Vector2 {
16
17
  /**
@@ -542,8 +543,8 @@ class Vector2 {
542
543
  * @returns {number}
543
544
  */
544
545
  hash() {
545
- const x = Math.sin(this.x) * 1367130550;
546
- const y = Math.sin(this.y) * 1367130550;
546
+ const x = computeHashFloat(this.x);
547
+ const y = computeHashFloat(this.y);
547
548
 
548
549
  let hash = ((x << 5) - x) + y;
549
550
 
@@ -680,6 +681,7 @@ Vector2.one = Object.freeze(new Vector2(1, 1));
680
681
  * @type {boolean}
681
682
  */
682
683
  Vector2.prototype.isVector2 = true;
684
+
683
685
  /**
684
686
  *
685
687
  * @param {number} x0
@@ -17,6 +17,8 @@ export class Tag {
17
17
 
18
18
  containsOneOf(values: string[]): boolean
19
19
 
20
+ hash(): number
21
+
20
22
  equals(other: Tag): boolean
21
23
 
22
24
  static find(tags: string[], ecd: EntityComponentDataset): number[]
@@ -3,8 +3,9 @@
3
3
  */
4
4
 
5
5
 
6
- import { computeStringHash } from "../../../core/primitives/strings/computeStringHash.js";
7
6
  import { assert } from "../../../core/assert.js";
7
+ import { isArrayEqualStrict } from "../../../core/collection/array/isArrayEqualStrict.js";
8
+ import { computeStringHash } from "../../../core/primitives/strings/computeStringHash.js";
8
9
 
9
10
  /**
10
11
  * Stores textual tags, useful for marking entities
@@ -12,7 +13,7 @@ import { assert } from "../../../core/assert.js";
12
13
  export class Tag {
13
14
  /**
14
15
  * @private
15
- * @type {String[]}
16
+ * @type {string[]}
16
17
  */
17
18
  values = [];
18
19
 
@@ -194,41 +195,31 @@ export class Tag {
194
195
  * @return {boolean}
195
196
  */
196
197
  equals(other) {
197
-
198
- const s0 = this.values;
199
-
200
- const s1 = other.values;
201
-
202
- const n0 = s0.length;
203
- const n1 = s1.length;
204
-
205
- if (n0 !== n1) {
206
- //wrong length
207
- return false;
208
- }
209
-
210
- for (let i = 0; i < n0; i++) {
211
- const v0 = s0[i];
212
- const v1 = s1[i];
213
-
214
- if (v0 !== v1) {
215
- return false;
216
- }
217
- }
218
-
219
- return true;
198
+ return isArrayEqualStrict(this.values, other.values);
220
199
  }
221
200
 
222
201
  toJSON() {
223
202
  return this.values;
224
203
  }
225
204
 
205
+ /**
206
+ *
207
+ * @param {string[]|string} json
208
+ */
226
209
  fromJSON(json) {
210
+
211
+ this.clear();
212
+
227
213
  if (typeof json === "string") {
228
- this.clear();
229
214
  this.add(json);
230
- } else if (Array.isArray(json)) {
231
- this.values = json;
215
+ } else {
216
+ assert.isArray(json, 'json');
217
+
218
+ const n = json.length;
219
+
220
+ for (let i = 0; i < n; i++) {
221
+ this.add(json[i]);
222
+ }
232
223
  }
233
224
  }
234
225
 
@@ -0,0 +1,47 @@
1
+ import Tag from "./Tag.js";
2
+
3
+ test("constructor", () => {
4
+ new Tag();
5
+ });
6
+
7
+ test("containsOneOf", () => {
8
+
9
+ const tag = Tag.fromJSON(['a', 'b']);
10
+
11
+ expect(tag.containsOneOf([])).toBe(false);
12
+ expect(tag.containsOneOf(['c'])).toBe(false);
13
+ expect(tag.containsOneOf(['a'])).toBe(true);
14
+ expect(tag.containsOneOf(['b'])).toBe(true);
15
+ expect(tag.containsOneOf(['a', 'b'])).toBe(true);
16
+
17
+ });
18
+
19
+ test("hash", () => {
20
+
21
+ const tag = Tag.fromJSON(['a', 'b']);
22
+
23
+ const hash = tag.hash();
24
+
25
+ expect(tag.hash()).toEqual(hash);
26
+
27
+ expect(typeof hash).toBe("number");
28
+ expect(Number.isInteger(hash)).toBe(true);
29
+ });
30
+
31
+ test("equals", () => {
32
+
33
+
34
+ const a = Tag.fromJSON(['a', 'b']);
35
+ const b = Tag.fromJSON([]);
36
+ const c = Tag.fromJSON(['a']);
37
+ const d = Tag.fromJSON(['b']);
38
+ const e = Tag.fromJSON(['a', 'b']);
39
+ const f = Tag.fromJSON(['a', 'c']);
40
+
41
+ expect(a.equals(b)).toBe(false);
42
+ expect(a.equals(c)).toBe(false);
43
+ expect(a.equals(d)).toBe(false);
44
+ expect(a.equals(e)).toBe(true);
45
+ expect(a.equals(f)).toBe(false);
46
+
47
+ });
@@ -208,6 +208,10 @@ export class FogOfWar {
208
208
  this.textureNeedsUpdate = true;
209
209
  }
210
210
 
211
+ concealAll(){
212
+ this.clear();
213
+ }
214
+
211
215
  /**
212
216
  *
213
217
  * @param {number} x
@@ -6,6 +6,9 @@ export class FogOfWarEditor extends ObjectEditor {
6
6
  properties: {
7
7
  revealAll: {
8
8
  type: Function
9
+ },
10
+ concealAll: {
11
+ type: Function
9
12
  }
10
13
  }
11
14
  };