@woosh/meep-engine 2.49.9 → 2.50.1

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 (170) hide show
  1. package/editor/actions/concrete/ArrayCopyAction.js +1 -1
  2. package/package.json +1 -1
  3. package/src/core/binary/BinaryBuffer.js +1 -1
  4. package/src/core/binary/BinaryBuffer.spec.js +128 -0
  5. package/src/core/binary/int32_to_binary_string.js +4 -1
  6. package/src/core/binary/int32_to_binary_string.spec.js +9 -0
  7. package/src/core/bvh2/BinaryNode.js +0 -30
  8. package/src/core/bvh2/binary/2/BinaryUint32BVH.js +1 -1
  9. package/src/core/bvh2/binary/IndexedBinaryBVH.js +1 -1
  10. package/src/core/bvh2/bvh3/ExplicitBinaryBoundingVolumeHierarchy.js +1 -1
  11. package/src/core/bvh2/bvh3/query/compute_tight_near_far_clipping_planes.js +1 -1
  12. package/src/core/cache/Cache.js +31 -29
  13. package/src/core/cache/Cache.spec.js +4 -1
  14. package/src/core/collection/HashMap.js +1 -1
  15. package/src/core/collection/array/{copyArray.js → array_copy.js} +1 -24
  16. package/src/core/collection/array/array_copy_entire.js +21 -0
  17. package/src/core/collection/array/typed/typed_array_copy.js +1 -1
  18. package/src/core/collection/queue/Deque.d.ts +4 -0
  19. package/src/core/collection/queue/Deque.js +5 -7
  20. package/src/core/collection/queue/Deque.spec.js +107 -0
  21. package/src/core/collection/table/RowFirstTable.js +1 -1
  22. package/src/core/geom/2d/aabb/AABB2.d.ts +14 -0
  23. package/src/core/geom/2d/aabb/AABB2.js +9 -7
  24. package/src/core/geom/2d/aabb/AABB2.spec.js +100 -0
  25. package/src/core/geom/2d/aabb/aabb2_compute_center_from_multiple.spec.js +11 -0
  26. package/src/core/geom/2d/aabb/aabb2_compute_overlap.spec.js +56 -0
  27. package/src/core/geom/2d/aabb/aabb2_contains.spec.js +40 -0
  28. package/src/core/geom/2d/bvh/Node2.js +1 -1
  29. package/src/core/geom/2d/convex-hull/fixed_convex_hull_humus.js +1 -1
  30. package/src/core/geom/2d/convex-hull/fixed_convex_hull_relaxation.js +1 -1
  31. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_2d.js +35 -0
  32. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_array_2d.js +51 -0
  33. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_vectors_2d.js +15 -0
  34. package/src/core/geom/2d/line/line_segment_compute_line_segment_intersection_vectors_array_2d.js +30 -0
  35. package/src/core/geom/2d/line/line_segment_line_segment_intersection_exists_2d.js +29 -0
  36. package/src/core/geom/3d/aabb/AABB3.d.ts +4 -0
  37. package/src/core/geom/3d/aabb/AABB3.spec.js +30 -0
  38. package/src/core/geom/3d/aabb/aabb3_detailed_volume_intersection.js +4 -4
  39. package/src/core/geom/3d/frustum/frustum3_computeNearestPointToPoint.js +5 -5
  40. package/src/core/geom/3d/matrix/m4_make_translation.js +1 -1
  41. package/src/core/geom/3d/plane/is_point_within_planes.js +1 -1
  42. package/src/core/geom/3d/plane/lerp_planes_to_array.js +2 -0
  43. package/src/core/geom/3d/plane/{plane_computeConvex3PlaneIntersection.js → plane3_compute_convex_3_plane_intersection.js} +1 -1
  44. package/src/core/geom/3d/plane/{plane3_computeLineSegmentIntersection.js → plane3_compute_line_segment_intersection.js} +1 -1
  45. package/src/core/geom/3d/plane/{computePlanePlaneIntersection.js → plane3_compute_plane_intersection.js} +15 -11
  46. package/src/core/geom/3d/plane/{computePlaneLineIntersection.js → plane3_compute_ray_intersection.js} +5 -1
  47. package/src/core/geom/3d/plane/plane3_intersect_plane.js +14 -0
  48. package/src/core/geom/3d/plane/{plane_three_compute_convex3_plane_intersection.js → plane3_three_compute_convex_3_plane_intersection.js} +7 -4
  49. package/src/core/geom/3d/plane/planeRayIntersection.js +2 -2
  50. package/src/core/geom/3d/sphere/harmonics/sh3_dering_optimize_positive.js +1 -1
  51. package/src/core/geom/3d/tetrahedra/TetrahedralMesh.js +1 -1
  52. package/src/core/geom/3d/tetrahedra/compute_bounding_simplex_3d.js +5 -5
  53. package/src/core/geom/3d/tetrahedra/compute_circumsphere.js +1 -1
  54. package/src/core/geom/3d/tetrahedra/delaunay/fill_in_a_cavity.js +1 -1
  55. package/src/core/geom/3d/topology/bounds/computeTriangleClusterNormalBoundingCone.js +1 -1
  56. package/src/core/geom/3d/topology/expandConnectivityByLocality.js +1 -1
  57. package/src/core/geom/3d/topology/struct/binary/BinaryTopology.js +1 -1
  58. package/src/core/geom/Quaternion.d.ts +11 -0
  59. package/src/core/geom/Quaternion.js +36 -27
  60. package/src/core/geom/Quaternion.spec.js +141 -0
  61. package/src/core/geom/Vector2.d.ts +5 -1
  62. package/src/core/geom/Vector2.js +24 -0
  63. package/src/core/geom/Vector3.d.ts +6 -0
  64. package/src/core/geom/Vector3.spec.js +60 -0
  65. package/src/core/graph/GraphUtils.js +4 -2
  66. package/src/core/graph/layout/CircleLayout.js +4 -2
  67. package/src/core/math/vector_nd_dot.js +16 -0
  68. package/src/core/math/{normalizeArrayVector.js → vector_nd_normalize.js} +3 -3
  69. package/src/core/math/{normalizeArrayVector.spec.js → vector_nd_normalize.spec.js} +3 -3
  70. package/src/core/process/PromiseWatcher.spec.js +1 -1
  71. package/src/engine/animation/curve/compression/downsample_float_array_curve_by_error.js +1 -1
  72. package/src/engine/ecs/EntityBlueprint.d.ts +14 -0
  73. package/src/engine/ecs/EntityBlueprint.js +2 -2
  74. package/src/engine/ecs/EntityBlueprint.spec.js +52 -0
  75. package/src/engine/ecs/EntityBuilder.js +8 -0
  76. package/src/engine/ecs/EntityManager.d.ts +1 -0
  77. package/src/engine/ecs/EntityManager.js +17 -213
  78. package/src/engine/ecs/EntityManager.spec.js +62 -1
  79. package/src/engine/ecs/System.js +8 -2
  80. package/src/engine/ecs/fow/FogOfWar.js +1 -1
  81. package/src/engine/ecs/guid/GUID.js +1 -1
  82. package/src/engine/ecs/terrain/ecs/splat/SplatMapping.js +1 -1
  83. package/src/engine/ecs/terrain/overlay/TerrainOverlay.js +1 -1
  84. package/src/engine/ecs/terrain/tiles/TerrainTile.js +1 -1
  85. package/src/engine/ecs/transform/Transform.d.ts +2 -0
  86. package/src/engine/ecs/transform/Transform.spec.js +63 -0
  87. package/src/engine/ecs/transform-attachment/TransformAttachment.d.ts +17 -1
  88. package/src/engine/ecs/transform-attachment/TransformAttachment.js +12 -2
  89. package/src/engine/ecs/transform-attachment/TransformAttachment.spec.js +103 -0
  90. package/src/engine/graphics/ecs/camera/Camera.js +2 -2
  91. package/src/engine/graphics/ecs/path/entity/EntityPath.js +1 -1
  92. package/src/engine/graphics/ecs/path/tube/build/computeFrenetFrames.js +1 -1
  93. package/src/engine/graphics/geometry/MikkT/GenerateTSpaces.js +1 -1
  94. package/src/engine/graphics/geometry/MikkT/m_getNormal.js +1 -1
  95. package/src/engine/graphics/geometry/MikkT/m_getTexCoord.js +1 -1
  96. package/src/engine/graphics/geometry/bvh/buffered/BVHGeometryRaycaster.js +1 -1
  97. package/src/engine/graphics/geometry/instancing/InstancedMeshGroup.js +1 -1
  98. package/src/engine/graphics/geometry/optimization/merge/merge_geometry_hierarchy.js +1 -1
  99. package/src/engine/graphics/impostors/octahedral/util/build_cutout_from_atlas_by_alpha.js +1 -1
  100. package/src/engine/graphics/particles/particular/engine/utils/volume/AttributeValue.js +1 -1
  101. package/src/engine/graphics/render/Lines.js +1 -1
  102. package/src/engine/graphics/render/buffer/simple-fx/taa/TemporalSupersamplingRenderPlugin.js +1 -1
  103. package/src/engine/graphics/render/forward_plus/LightManager.js +1 -1
  104. package/src/engine/graphics/render/forward_plus/computeFrustumCorners.js +10 -10
  105. package/src/engine/graphics/render/forward_plus/model/Decal.js +1 -1
  106. package/src/engine/graphics/render/forward_plus/prototype/prototypeLightManager.js +1 -1
  107. package/src/engine/graphics/render/gizmo/GizmoShapeRenderingInterface.js +1 -1
  108. package/src/engine/graphics/render/layers/RenderLayerUtils.js +3 -3
  109. package/src/engine/graphics/render/view/CameraView.js +1 -1
  110. package/src/engine/graphics/render/visibility/hiz/query/BatchOcclusionQuery.js +1 -1
  111. package/src/engine/graphics/render/webgpu/sample/MeshInstance.js +1 -1
  112. package/src/engine/graphics/sh3/LightProbeVolume.js +1 -1
  113. package/src/engine/graphics/sh3/path_tracer/PathTracedMesh.js +1 -1
  114. package/src/engine/graphics/sh3/path_tracer/PathTracer.js +1 -1
  115. package/src/engine/graphics/sh3/path_tracer/make_sky_hosek.js +1 -1
  116. package/src/engine/graphics/sh3/prototypeSH3Probe.js +1 -1
  117. package/src/engine/graphics/texture/3d/scs3d_read_2d_slice.js +1 -1
  118. package/src/engine/graphics/texture/CanvasClone.js +5 -1
  119. package/src/engine/graphics/texture/sampler/Sampler2D.js +14 -75
  120. package/src/engine/graphics/texture/sampler/bicubic.js +19 -19
  121. package/src/engine/graphics/texture/sampler/convertSampler2D2DataURL.spec.js +10 -0
  122. package/src/engine/graphics/texture/sampler/copy_Sampler2D_channel_data.spec.js +90 -0
  123. package/src/engine/graphics/texture/sampler/differenceSampler.js +13 -8
  124. package/src/engine/graphics/texture/sampler/distance/computeSignedDistanceField_Chamfer.js +140 -0
  125. package/src/engine/graphics/texture/sampler/distance/computeSignedDistanceField_NaiveFlood.js +130 -0
  126. package/src/engine/graphics/texture/sampler/distance/computeUnsignedDistanceField.js +10 -0
  127. package/src/engine/graphics/texture/sampler/distance/computeUnsignedDistanceField.spec.js +183 -0
  128. package/src/engine/graphics/texture/sampler/distance/computeUnsignedDistanceField_Chamfer.js +133 -0
  129. package/src/engine/graphics/texture/sampler/filter/mitchell.js +4 -0
  130. package/src/engine/graphics/texture/sampler/loadSampler2D.js +5 -2
  131. package/src/engine/graphics/texture/sampler/resize/sampler2d_downsample_mipmap.js +8 -3
  132. package/src/engine/graphics/texture/sampler/resize/sampler2d_downsample_mipmap.spec.js +13 -0
  133. package/src/engine/graphics/texture/sampler/sampler2d_channel_compute_min_indices.js +58 -0
  134. package/src/engine/graphics/trail/TemporalPath.js +0 -36
  135. package/src/engine/intelligence/behavior/composite/ParallelBehavior.spec.js +12 -12
  136. package/src/engine/intelligence/behavior/composite/SequenceBehavior.spec.js +17 -0
  137. package/src/engine/intelligence/behavior/primitive/SucceedingBehavior.js +3 -1
  138. package/src/engine/knowledge/database/StaticKnowledgeDataTable.d.ts +7 -1
  139. package/src/engine/knowledge/database/StaticKnowledgeDataTable.spec.js +21 -0
  140. package/src/engine/knowledge/database/StaticKnowledgeDataTableDescriptor.d.ts +2 -2
  141. package/src/engine/logging/ConsoleLoggerBackend.js +4 -0
  142. package/src/engine/logging/VoidLoggerBackend.js +12 -0
  143. package/src/engine/navigation/ecs/components/computeCatmullRomSpline.js +1 -1
  144. package/src/engine/navigation/ecs/components/computeCatmullRomSplineUniformDistance.js +1 -1
  145. package/src/engine/physics/cannon/CannonJSPhysicsSystem.js +1 -1
  146. package/src/engine/save/GameStateLoader.js +1 -1
  147. package/src/engine/scene/Scene.d.ts +2 -0
  148. package/src/engine/scene/Scene.js +2 -2
  149. package/src/engine/scene/Scene.spec.js +20 -0
  150. package/src/engine/scene/SceneManager.d.ts +4 -0
  151. package/src/engine/scene/SceneManager.js +46 -23
  152. package/src/engine/scene/SceneManager.spec.js +131 -0
  153. package/src/engine/sound/material/detector/terrain/TerrainSoundMaterialSurfaceDetector.js +2 -2
  154. package/src/engine/ui/GUIEngine.js +1 -1
  155. package/src/generation/grid/GridData.js +8 -2
  156. package/src/generation/grid/GridData.spec.js +5 -0
  157. package/src/generation/grid/generation/util/buildUnsignedDistanceField.js +3 -1
  158. package/src/generation/markers/MarkerNode.js +2 -2
  159. package/src/generation/markers/actions/MarkerNodeActionEntityPlacement.js +1 -1
  160. package/src/generation/theme/AreaMask.js +3 -1
  161. package/src/view/elements/progress/RectangularPieProgressView.js +8 -6
  162. package/src/view/minimap/dom/MinimapCameraView.js +3 -3
  163. package/src/core/geom/2d/LineSegment2.js +0 -175
  164. package/src/core/geom/3d/plane/computePlaneRayIntersection.js +0 -55
  165. package/src/core/geom/Matrix4.js +0 -275
  166. package/src/engine/graphics/texture/sampler/distanceField.js +0 -411
  167. package/src/engine/graphics/texture/sampler/distanceField.spec.js +0 -184
  168. package/src/engine/physics/cannon/cannon.min.js +0 -27
  169. package/src/generation/grid/MarkerMatchCounter.js +0 -25
  170. /package/src/engine/physics/spring/{Spring.js → computeHookeForce.js} +0 -0
@@ -45,3 +45,63 @@ test('addVectors', () => {
45
45
  expect(ut.y).toBe(14);
46
46
  expect(ut.z).toBe(18);
47
47
  });
48
+
49
+ test("equals", () => {
50
+ expect(new Vector3(1, -2, 3).equals(new Vector3(1, -2, 3)))
51
+ .toBe(true);
52
+
53
+ expect(new Vector3(1, -2, 3).equals(new Vector3(5, -2, 3)))
54
+ .toBe(false);
55
+
56
+ expect(new Vector3(1, -2, 3).equals(new Vector3(1, 5, 3)))
57
+ .toBe(false);
58
+
59
+ expect(new Vector3(1, -2, 3).equals(new Vector3(1, -2, 5)))
60
+ .toBe(false);
61
+ });
62
+
63
+ test("roughlyEquals", () => {
64
+ expect(new Vector3(1, -2, 3).roughlyEquals(new Vector3(1, -2, 3), 0))
65
+ .toBe(true);
66
+
67
+ expect(new Vector3(1, -2, 3).roughlyEquals(new Vector3(1, -2, 3), 0.1))
68
+ .toBe(true);
69
+
70
+ expect(new Vector3(1, -2, 3).roughlyEquals(new Vector3(1.01, -2, 3), 0.1))
71
+ .toBe(true);
72
+
73
+ expect(new Vector3(1, -2, 3).roughlyEquals(new Vector3(0.99, -2, 3), 0.1))
74
+ .toBe(true);
75
+
76
+ expect(new Vector3(1, -2, 3).roughlyEquals(new Vector3(0.89, -2, 3), 0.1))
77
+ .toBe(false);
78
+
79
+ expect(new Vector3(1, -2, 3).roughlyEquals(new Vector3(1.11, -2, 3), 0.1))
80
+ .toBe(false);
81
+
82
+ // Y
83
+ expect(new Vector3(1, -2, 3).roughlyEquals(new Vector3(1, -2.01, 3), 0.1))
84
+ .toBe(true);
85
+
86
+ expect(new Vector3(1, -2, 3).roughlyEquals(new Vector3(1, -1.99, 3), 0.1))
87
+ .toBe(true);
88
+
89
+ expect(new Vector3(1, -2, 3).roughlyEquals(new Vector3(1, -2.11, 3), 0.1))
90
+ .toBe(false);
91
+
92
+ expect(new Vector3(1, -2, 3).roughlyEquals(new Vector3(1, -1.89, 3), 0.1))
93
+ .toBe(false);
94
+
95
+ // Z
96
+ expect(new Vector3(1, -2, 3).roughlyEquals(new Vector3(1, -2, 3.01), 0.1))
97
+ .toBe(true);
98
+
99
+ expect(new Vector3(1, -2, 3).roughlyEquals(new Vector3(1, -2, 2.99), 0.1))
100
+ .toBe(true);
101
+
102
+ expect(new Vector3(1, -2, 3).roughlyEquals(new Vector3(1, -2, 2.89), 0.1))
103
+ .toBe(false);
104
+
105
+ expect(new Vector3(1, -2, 3).roughlyEquals(new Vector3(1, -2, 3.11), 0.1))
106
+ .toBe(false);
107
+ });
@@ -3,7 +3,9 @@
3
3
  */
4
4
 
5
5
 
6
- import { computeLine2Intersection } from "../geom/2d/LineSegment2.js";
6
+ import {
7
+ line_segment_compute_line_segment_intersection_vectors_array_2d
8
+ } from "../geom/2d/line/line_segment_compute_line_segment_intersection_vectors_array_2d.js";
7
9
 
8
10
  const Utils = {};
9
11
 
@@ -155,7 +157,7 @@ function graph2paths(graph, thickness) {
155
157
  const l = edges.length;
156
158
  for (; i < l; i++) {
157
159
  const edge = edges[i];
158
- if (computeLine2Intersection(from, to, edge.first, edge.second)) {
160
+ if (line_segment_compute_line_segment_intersection_vectors_array_2d(from, to, edge.first, edge.second)) {
159
161
  return true;
160
162
  }
161
163
  }
@@ -6,7 +6,6 @@
6
6
  import { assert } from "../../assert.js";
7
7
  import Circle from "../../geom/2d/circle/Circle.js";
8
8
  import AABB2 from "../../geom/2d/aabb/AABB2.js";
9
- import { line2SegmentsIntersect } from "../../geom/2d/LineSegment2.js";
10
9
  import Vector2, { v2_distance } from "../../geom/Vector2.js";
11
10
  import { max2 } from "../../math/max2.js";
12
11
  import { min2 } from "../../math/min2.js";
@@ -14,6 +13,9 @@ import { computeDisconnectedSubGraphs } from "./computeDisconnectedSubGraphs.js"
14
13
  import { Connection } from "./Connection.js";
15
14
  import { resolveAABB2Overlap } from "./box/resolveAABB2Overlap.js";
16
15
  import { applyCentralGravityAABB2 } from "./box/applyCentralGravityAABB2.js";
16
+ import {
17
+ line_segment_line_segment_intersection_exists_2d
18
+ } from "../../geom/2d/line/line_segment_line_segment_intersection_exists_2d.js";
17
19
 
18
20
 
19
21
  /**
@@ -364,7 +366,7 @@ function computeNumberOfCrossOvers(edges, numEdges) {
364
366
  const b0 = e1.source;
365
367
  const b1 = e1.target;
366
368
 
367
- if (line2SegmentsIntersect(
369
+ if (line_segment_line_segment_intersection_exists_2d(
368
370
  a0.x, a0.y,
369
371
  a1.x, a1.y,
370
372
  b0.x, b0.y,
@@ -0,0 +1,16 @@
1
+ /**
2
+ * N-dimensional vector dot product
3
+ * @param {number[]|Float32Array|Float64Array} a
4
+ * @param {number[]|Float32Array|Float64Array} b
5
+ * @param {number} n number of dimensions
6
+ * @return {number}
7
+ */
8
+ export function vector_nd_dot(a, b, n) {
9
+ let result = 0;
10
+
11
+ for (let i = 0; i < n; i++) {
12
+ result += a[i] * b[i]
13
+ }
14
+
15
+ return result;
16
+ }
@@ -1,10 +1,10 @@
1
1
  /**
2
2
  * Assuming the input is an N-dimension vector, normalizes the vector to magnitude of 1
3
- * @param {number[]|Float32Array} result
4
- * @param {number[]|Float32Array} data
3
+ * @param {number[]|Float32Array|Float64Array} result
4
+ * @param {number[]|Float32Array|Float64Array} data
5
5
  * @param {number} [length] number of dimensions
6
6
  */
7
- export function normalizeArrayVector(result, data, length = data.length) {
7
+ export function vector_nd_normalize(result, data, length = data.length) {
8
8
 
9
9
  let magnitude2 = 0;
10
10
 
@@ -1,15 +1,15 @@
1
- import { normalizeArrayVector } from "./normalizeArrayVector.js";
1
+ import { vector_nd_normalize } from "./vector_nd_normalize.js";
2
2
 
3
3
  test("1d vector normalization", () => {
4
4
  const v = [7];
5
5
 
6
- normalizeArrayVector(v, v, 1);
6
+ vector_nd_normalize(v, v, 1);
7
7
 
8
8
  expect(v[0]).toBeCloseTo(1);
9
9
 
10
10
  v[0] = -13;
11
11
 
12
- normalizeArrayVector(v, v, 1);
12
+ vector_nd_normalize(v, v, 1);
13
13
 
14
14
  expect(v[0]).toBeCloseTo(-1);
15
15
  });
@@ -16,7 +16,7 @@ function trigger() {
16
16
  return {
17
17
  promise,
18
18
  reject(r) {
19
- _reject(r)
19
+ setTimeout(() => _reject(r), 1);
20
20
  },
21
21
  resolve(v) {
22
22
  _resolve(v);
@@ -6,7 +6,7 @@ import { lerp } from "../../../../core/math/lerp.js";
6
6
  import { min3 } from "../../../../core/math/min3.js";
7
7
  import { max3 } from "../../../../core/math/max3.js";
8
8
  import { downsample_float_array } from "./downsample_float_array.js";
9
- import { array_copy } from "../../../../core/collection/array/copyArray.js";
9
+ import { array_copy } from "../../../../core/collection/array/array_copy.js";
10
10
  import { isPowerOfTwo } from "../../../../core/math/isPowerOrTwo.js";
11
11
 
12
12
  /**
@@ -1,3 +1,17 @@
1
+ import EntityBuilder from "./EntityBuilder";
2
+
3
+ interface Type<T> extends Function {
4
+ new(...args: any[]): T;
5
+ }
6
+
1
7
  export class EntityBlueprint {
2
8
  static from(components: any[]): EntityBlueprint
9
+
10
+ add<T>(component: T): void
11
+
12
+ addJSON<T>(klass: Type<T>, json: any): void
13
+
14
+ clear(): void
15
+
16
+ build(seed?: object): EntityBuilder
3
17
  }
@@ -140,10 +140,10 @@ export class EntityBlueprint {
140
140
 
141
141
 
142
142
  /**
143
- *
143
+ * @param {object} [templateSeed]
144
144
  * @return {EntityBuilder}
145
145
  */
146
- buildEntityBuilder(templateSeed) {
146
+ build(templateSeed) {
147
147
  const eb = new EntityBuilder();
148
148
 
149
149
  this.componentnts.forEach((template, ComponentClass) => {
@@ -0,0 +1,52 @@
1
+ import { EntityBlueprint } from "./EntityBlueprint.js";
2
+ import EntityBuilder from "./EntityBuilder.js";
3
+
4
+ test("constructor does not throw", () => {
5
+
6
+ expect(() => new EntityBlueprint()).not.toThrow();
7
+
8
+ });
9
+
10
+ test("build empty", () => {
11
+ const blueprint = new EntityBlueprint();
12
+
13
+ const entity = blueprint.build();
14
+
15
+ expect(entity).toBeDefined();
16
+ expect(entity).toBeInstanceOf(EntityBuilder);
17
+ expect(entity.count).toEqual(0);
18
+ });
19
+
20
+ class DummyComponent {
21
+ a = 0
22
+
23
+ fromJSON({ a }) {
24
+ this.a = a;
25
+ }
26
+ }
27
+
28
+ test("a copy of the added component ends up on built entity", () => {
29
+
30
+ const blueprint = new EntityBlueprint();
31
+
32
+ blueprint.addJSON(DummyComponent, { a: 7 });
33
+
34
+ const entity = blueprint.build();
35
+
36
+ const retrieved = entity.getComponent(DummyComponent);
37
+
38
+ expect(retrieved).toBeInstanceOf(DummyComponent);
39
+ expect(retrieved.a).toEqual(7);
40
+ });
41
+
42
+ test("seed template", () => {
43
+ const blueprint = new EntityBlueprint();
44
+
45
+ blueprint.addJSON(DummyComponent, { a: '$x' });
46
+
47
+ const entity = blueprint.build({ x: 13 });
48
+
49
+ const component = entity.getComponent(DummyComponent);
50
+
51
+ expect(component.a).toEqual(13);
52
+ });
@@ -125,6 +125,14 @@ class EntityBuilder {
125
125
  }
126
126
  }
127
127
 
128
+ /**
129
+ * Number of attached components
130
+ * @return {number}
131
+ */
132
+ get count() {
133
+ return this.element.length;
134
+ }
135
+
128
136
  /**
129
137
  * @template T
130
138
  * @param {T} componentInstance
@@ -8,6 +8,7 @@ interface Type<T> extends Function {
8
8
 
9
9
  export class EntityManager {
10
10
  dataset: EntityComponentDataset
11
+ fixedUpdateStepSize: number
11
12
 
12
13
  getComponentTypeMap(): any[]
13
14
 
@@ -329,6 +329,9 @@ EntityManager.prototype.simulate = function (timeDelta) {
329
329
  const fixed_step = this.fixedUpdateStepSize;
330
330
  const accumulatedTime = this.systemAccumulatedFixedStepTime;
331
331
 
332
+ assert.notNaN(fixed_step, 'fixed_step');
333
+ assert.greaterThan(fixed_step, 0, 'fixed_step must be greater than 0');
334
+
332
335
  for (let i = 0; i < system_count; i++) {
333
336
 
334
337
  const system = systems[i];
@@ -337,7 +340,7 @@ EntityManager.prototype.simulate = function (timeDelta) {
337
340
  let accumulated_time = accumulatedTime.get(system) + timeDelta;
338
341
 
339
342
 
340
- while (accumulated_time > fixed_step) {
343
+ while (accumulated_time >= fixed_step) {
341
344
 
342
345
  try {
343
346
  system.fixedUpdate(fixed_step)
@@ -458,9 +461,10 @@ function validateSystem(system) {
458
461
  /**
459
462
  * If the {@link EntityManager} is already started, the system will be started automatically before being added
460
463
  * @param {System} system
464
+ * @returns {Promise}
461
465
  * @throws {IllegalStateException}
462
466
  */
463
- EntityManager.prototype.addSystem = async function (system) {
467
+ EntityManager.prototype.addSystem = function (system) {
464
468
  assert.defined(system, "system");
465
469
  assert.isInstanceOf(system, System, 'system', 'System');
466
470
 
@@ -469,7 +473,7 @@ EntityManager.prototype.addSystem = async function (system) {
469
473
  if (existing !== null) {
470
474
  if (existing === system) {
471
475
  //system already added, do nothing
472
- return;
476
+ return Promise.resolve();
473
477
  } else {
474
478
  throw new IllegalStateException(`Another instance of system '${computeSystemName(system)}' is already registered`);
475
479
  }
@@ -508,7 +512,7 @@ EntityManager.prototype.addSystem = async function (system) {
508
512
  if (this.state === EntityManagerState.Running) {
509
513
  //initialize the system
510
514
  startup_promise = new Promise((resolve, reject) => {
511
- system.startup(this, resolve, reject);
515
+ this.startSystem(system, resolve, reject);
512
516
  });
513
517
  } else {
514
518
  startup_promise = Promise.resolve();
@@ -526,13 +530,13 @@ EntityManager.prototype.addSystem = async function (system) {
526
530
 
527
531
  this.on.systemAdded.send1(system);
528
532
 
529
- await startup_promise;
533
+ return startup_promise;
530
534
  };
531
535
 
532
536
  /**
533
537
  *
534
538
  * @param {System} system
535
- * @returns {boolean}
539
+ * @returns {Promise<boolean>}
536
540
  */
537
541
  EntityManager.prototype.removeSystem = async function (system) {
538
542
  assert.defined(system, "system");
@@ -573,11 +577,13 @@ EntityManager.prototype.removeSystem = async function (system) {
573
577
  this.systemAccumulatedFixedStepTime.delete(system);
574
578
 
575
579
  this.on.systemRemoved.send1(system);
580
+
581
+ return true;
576
582
  };
577
583
 
578
584
 
579
585
  /**
580
- *
586
+ * @private
581
587
  * @param {System} system
582
588
  * @param {function(system: System)} successCallback
583
589
  * @param {function(reason:*)} errorCallback
@@ -614,13 +620,15 @@ EntityManager.prototype.stopSystem = function (system, successCallback, errorCal
614
620
  };
615
621
 
616
622
  /**
617
- *
623
+ * @private
618
624
  * @param {System} system
619
625
  * @param {function(system: System)} successCallback
620
626
  * @param {function(reason:*)} errorCallback
621
627
  */
622
628
  EntityManager.prototype.startSystem = function (system, successCallback, errorCallback) {
623
629
  assert.defined(system, "system");
630
+ assert.isFunction(successCallback, "successCallback");
631
+ assert.isFunction(errorCallback, "errorCallback");
624
632
 
625
633
  if (system.state.getValue() === System.State.RUNNING) {
626
634
  //system is already running
@@ -831,7 +839,7 @@ EntityManager.prototype.shutdown = function (readyCallback, errorCallback) {
831
839
 
832
840
  system.state.set(System.State.STOPPED);
833
841
 
834
- self.on.systemStopped.dispatch(system);
842
+ self.on.systemStopped.send1(system);
835
843
  if (readyCount === expectedReadyCount) {
836
844
  finalizeShutdown();
837
845
  }
@@ -870,210 +878,6 @@ EntityManager.prototype.shutdown = function (readyCallback, errorCallback) {
870
878
  });
871
879
  };
872
880
 
873
-
874
- /**
875
- * @deprecated
876
- * @returns {number}
877
- */
878
- EntityManager.prototype.createEntity = function () {
879
- console.warn("EntityManager.createEntity is deprecated");
880
-
881
- return this.dataset.createEntity();
882
- };
883
-
884
- /**
885
- * @deprecated
886
- * @param id
887
- */
888
- EntityManager.prototype.createEntitySpecific = function (id) {
889
- console.warn("EntityManager.createEntitySpecific is deprecated");
890
- this.dataset.createEntitySpecific(id);
891
- };
892
-
893
-
894
- /**
895
- * @deprecated
896
- * Remove association of specified component type from entity
897
- * @param {Number} entityId
898
- * @param {Number} componentType
899
- */
900
- EntityManager.prototype.removeComponentFromEntity = function (entityId, componentType) {
901
- console.warn("EntityManager.removeComponentFromEntity is deprecated");
902
-
903
- this.dataset.removeComponentFromEntityByIndex(entityId, componentType);
904
- };
905
-
906
- /**
907
- * @deprecated use dataset directly
908
- * Retrieves component instance associated with entity
909
- * @template T
910
- * @param {Number} entityId
911
- * @param {class.<T>} componentClass
912
- * @returns {T|null}
913
- * @nosideeffects
914
- */
915
- EntityManager.prototype.getComponent = function (entityId, componentClass) {
916
- console.warn("EntityManager.getComponent is deprecated");
917
-
918
- return this.dataset.getComponent(entityId, componentClass);
919
- };
920
-
921
- /**
922
- * @deprecated use {@link EntityComponentDataset.entityExists} instead
923
- * @param {number} entityIndex
924
- * @returns {boolean}
925
- */
926
- EntityManager.prototype.entityExists = function (entityIndex) {
927
- console.warn("EntityManager.entityExists is deprecated");
928
- if (this.dataset === null) {
929
- //no dataset - no entities
930
- return false;
931
- }
932
- return this.dataset.entityExists(entityIndex);
933
- };
934
-
935
-
936
- /**
937
- * @deprecated Use {@link EntityManager#dataset} direction
938
- * @param entity
939
- * @returns {Array}
940
- */
941
- EntityManager.prototype.getComponents = function (entity) {
942
- console.warn("EntityManager.getComponents is deprecated");
943
-
944
- return this.dataset.getAllComponents(entity);
945
- };
946
-
947
- /**
948
- * @deprecated
949
- * Retrieves component instance associated with entity
950
- * @param {Number} entityId
951
- * @param {Number} componentType
952
- * @returns {*|undefined} component of specified type or undefined if it was not found
953
- */
954
- EntityManager.prototype.getComponentByType = function (entityId, componentType) {
955
- console.warn("EntityManager.getComponentByType is deprecated");
956
- return this.dataset.getComponentByIndex(entityId, componentType);
957
- };
958
-
959
- /**
960
- * @deprecated
961
- * does traversal on a subset of entities which have specified components.
962
- * @example traverseEntities([Transform,Renderable,Tag],function(transform, renderable, tag, entity){ ... }, this);
963
- * @param {Array.<class>} classes
964
- * @param {Function} callback
965
- * @param {Object} [thisArg] specifies context object on which callbacks are to be called, optional
966
- */
967
- EntityManager.prototype.traverseEntities = function (classes, callback, thisArg) {
968
- console.warn("EntityManager.traverseEntities is deprecated");
969
-
970
- if (this.dataset === null) {
971
- //no data to traverse
972
- return;
973
- }
974
- this.dataset.traverseEntities(classes, callback, thisArg);
975
- };
976
-
977
- /**
978
- * @deprecated
979
- * @param entity
980
- * @param eventName
981
- * @param listener
982
- */
983
- EntityManager.prototype.addEntityEventListener = function (entity, eventName, listener) {
984
- console.warn("EntityManager.addEntityEventListener is deprecated");
985
- this.dataset.addEntityEventListener(entity, eventName, listener);
986
- };
987
-
988
- /**
989
- * @deprecated
990
- * @param {number} entity
991
- * @param {string} eventName
992
- * @param {function} listener
993
- */
994
- EntityManager.prototype.removeEntityEventListener = function (entity, eventName, listener) {
995
- console.warn("EntityManager.removeEntityEventListener is deprecated");
996
- this.dataset.removeEntityEventListener(entity, eventName, listener);
997
- };
998
-
999
- /**
1000
- * @deprecated use dataset directly instead
1001
- * @param entity
1002
- * @param eventName
1003
- * @param event
1004
- */
1005
- EntityManager.prototype.sendEvent = function (entity, eventName, event) {
1006
- console.warn("EntityManager.sendEvent is deprecated");
1007
- this.dataset.sendEvent(entity, eventName, event);
1008
- };
1009
-
1010
- /**
1011
- * @deprecated
1012
- * @param {function} klazz
1013
- * @param {function(component: *, entity: number):boolean} callback
1014
- * @param {*} [thisArg]
1015
- * @deprecated
1016
- */
1017
- EntityManager.prototype.traverseComponents = function (klazz, callback, thisArg) {
1018
- console.warn("EntityManager.traverseComponents is deprecated");
1019
- if (this.dataset !== null) {
1020
- this.dataset.traverseComponents(klazz, callback, thisArg);
1021
- }
1022
- };
1023
-
1024
- /**
1025
- * @deprecated Use {@link #getSystem} instead
1026
- * @template T,C
1027
- * @param {C} klazz
1028
- * @returns {System|T}
1029
- */
1030
- EntityManager.prototype.getOwnerSystemByComponentClass = function (klazz) {
1031
-
1032
- console.warn("EntityManager.getOwnerSystemByComponentClass is deprecated, use .getSystem instead");
1033
- const index = this.getOwnerSystemIdByComponentClass(klazz);
1034
- return this.systems[index];
1035
- };
1036
-
1037
- /**
1038
- * @deprecated
1039
- * @param {function} clazz
1040
- * @returns {number} value >= 0, representing system Id, or -1 if system was not found
1041
- */
1042
- EntityManager.prototype.getOwnerSystemIdByComponentClass = function (clazz) {
1043
- console.warn("EntityManager.getOwnerSystemIdByComponentClass is deprecated, use .getSystem instead");
1044
-
1045
- const systems = this.systems;
1046
- let i = 0;
1047
- const l = systems.length;
1048
- for (; i < l; i++) {
1049
- if (systems[i].componentClass === clazz) {
1050
- return i;
1051
- }
1052
- }
1053
- return -1;
1054
- };
1055
-
1056
-
1057
- /**
1058
- * same as getComponent when component exists, if component is not associated with the entity, callback will be invoked once when it is added.
1059
- * @param {Number} entityId
1060
- * @param {Class} componentClass
1061
- * @param {function} callback
1062
- * @param {*} [thisArg]
1063
- */
1064
- EntityManager.prototype.getComponentAsync = function (entityId, componentClass, callback, thisArg) {
1065
- console.warn("EntityManager.getComponentAsync is deprecated");
1066
-
1067
- const dataset = this.dataset;
1068
-
1069
- if (dataset === undefined) {
1070
- throw new Error('No dataset attached');
1071
- }
1072
-
1073
- dataset.getComponentAsync(entityId, componentClass, callback, thisArg);
1074
-
1075
- };
1076
-
1077
881
  export {
1078
882
  EventType,
1079
883
  EntityManager
@@ -1,6 +1,7 @@
1
1
  import { EntityManager } from "./EntityManager.js";
2
- import { System } from "./System.js";
2
+ import { System, SystemState } from "./System.js";
3
3
  import { jest } from '@jest/globals';
4
+ import { IllegalStateException } from "../../core/fsm/exceptions/IllegalStateException.js";
4
5
 
5
6
  /**
6
7
  *
@@ -97,3 +98,63 @@ test("call to 'simulate' propagate to registered system", () => {
97
98
  expect(update).toHaveBeenLastCalledWith(7);
98
99
  });
99
100
  });
101
+
102
+
103
+ test("call to 'simulate' ticks fixed update correctly", async () => {
104
+
105
+ const dummySystem = new DummySystem();
106
+ const fixedUpdate = jest.spyOn(dummySystem, 'fixedUpdate');
107
+
108
+ const em = await makeEm([dummySystem]);
109
+
110
+ em.fixedUpdateStepSize = 1.1;
111
+
112
+ em.simulate(3.3001);
113
+
114
+ expect(fixedUpdate).toHaveBeenCalledTimes(3);
115
+ expect(fixedUpdate).toHaveBeenLastCalledWith(1.1);
116
+ });
117
+
118
+ test("hasSystem", async () => {
119
+
120
+ const dummySystem = new DummySystem();
121
+ const em = await makeEm([]);
122
+
123
+ expect(em.hasSystem(DummySystem)).toBe(false);
124
+
125
+ await em.addSystem(dummySystem);
126
+
127
+ expect(em.hasSystem(DummySystem)).toBe(true);
128
+ });
129
+
130
+ test("addSystem", async () => {
131
+ const em = await makeEm([]);
132
+
133
+ const s1 = new DummySystem();
134
+
135
+ await em.addSystem(s1);
136
+
137
+ expect(s1.state.get()).toEqual(SystemState.RUNNING)
138
+
139
+ // system is already added, expect silent return
140
+ expect(() => em.addSystem(s1)).not.toThrow();
141
+
142
+ // 2 systems of the same class are not allowed
143
+ expect(() => em.addSystem(new DummySystem())).toThrow(IllegalStateException);
144
+ });
145
+
146
+ test("removeSystem", async () => {
147
+
148
+ const system = new DummySystem();
149
+
150
+ const em = await makeEm([system]);
151
+
152
+ expect(await em.removeSystem(system)).toBe(true);
153
+
154
+ expect(em.hasSystem(DummySystem)).toBe(false);
155
+
156
+ expect(system.state.get()).toEqual(SystemState.STOPPED);
157
+
158
+ // Try again, this time we expect nothing to happen
159
+ expect(await em.removeSystem(system)).toEqual(false);
160
+ });