@woosh/meep-engine 2.156.0 → 2.157.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 (654) hide show
  1. package/README.md +1 -3
  2. package/editor/view/ecs/components/common/AutoCanvasView.js +100 -53
  3. package/editor/view/ecs/components/common/TextController.js +59 -0
  4. package/editor/view/node-graph/NodeGraphCamera.js +90 -0
  5. package/editor/view/node-graph/NodeGraphEditorView.js +121 -22
  6. package/editor/view/node-graph/NodeGraphSelection.js +89 -0
  7. package/editor/view/node-graph/NodeGraphView.js +669 -453
  8. package/editor/view/node-graph/NodeView.js +211 -135
  9. package/editor/view/node-graph/actions/ConnectionCreateAction.js +53 -0
  10. package/editor/view/node-graph/actions/ConnectionDeleteAction.js +36 -0
  11. package/editor/view/node-graph/actions/NodeDeleteAction.js +88 -0
  12. package/editor/view/node-graph/actions/NodeParameterSetAction.js +52 -0
  13. package/editor/view/node-graph/actions/NodesMoveAction.js +41 -0
  14. package/editor/view/node-graph/actions/SelectionSetAction.js +60 -0
  15. package/editor/view/node-graph/connection_wire_geometry.js +107 -0
  16. package/package.json +1 -1
  17. package/samples/generation/SampleGenerator0.js +8 -1
  18. package/src/core/binary/reinterpret_float32_as_uint32.d.ts +7 -0
  19. package/src/core/binary/reinterpret_float32_as_uint32.d.ts.map +1 -0
  20. package/src/core/binary/reinterpret_float32_as_uint32.js +13 -0
  21. package/src/core/binary/reinterpret_uint32_as_float32.d.ts +7 -0
  22. package/src/core/binary/reinterpret_uint32_as_float32.d.ts.map +1 -0
  23. package/src/core/binary/reinterpret_uint32_as_float32.js +14 -0
  24. package/src/core/bvh2/bvh3/ebvh_build_for_geometry_incremental.d.ts.map +1 -1
  25. package/src/core/bvh2/bvh3/ebvh_build_for_geometry_incremental.js +1 -3
  26. package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_sphere.d.ts +12 -0
  27. package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_sphere.d.ts.map +1 -0
  28. package/src/core/bvh2/bvh3/query/bvh_query_user_data_overlaps_sphere.js +92 -0
  29. package/src/core/bvh8/BVH8.d.ts +127 -0
  30. package/src/core/bvh8/BVH8.d.ts.map +1 -0
  31. package/src/core/bvh8/BVH8.js +436 -0
  32. package/src/core/bvh8/NOTES.md +63 -0
  33. package/src/core/bvh8/build/BVH8Converter.d.ts +59 -0
  34. package/src/core/bvh8/build/BVH8Converter.d.ts.map +1 -0
  35. package/src/core/bvh8/build/BVH8Converter.js +588 -0
  36. package/src/core/bvh8/build/NodeProxy.d.ts +66 -0
  37. package/src/core/bvh8/build/NodeProxy.d.ts.map +1 -0
  38. package/src/core/bvh8/build/NodeProxy.js +308 -0
  39. package/src/core/bvh8/build/TriangleCluster.d.ts +29 -0
  40. package/src/core/bvh8/build/TriangleCluster.d.ts.map +1 -0
  41. package/src/core/bvh8/build/TriangleCluster.js +123 -0
  42. package/src/core/bvh8/build/aabb3_compute_merge_cost.d.ts +8 -0
  43. package/src/core/bvh8/build/aabb3_compute_merge_cost.d.ts.map +1 -0
  44. package/src/core/bvh8/build/aabb3_compute_merge_cost.js +29 -0
  45. package/src/core/bvh8/build/aabb3_from_triangle_by_index.d.ts +10 -0
  46. package/src/core/bvh8/build/aabb3_from_triangle_by_index.d.ts.map +1 -0
  47. package/src/core/bvh8/build/aabb3_from_triangle_by_index.js +18 -0
  48. package/src/core/bvh8/build/bvh8_build_for_geometry.d.ts +10 -0
  49. package/src/core/bvh8/build/bvh8_build_for_geometry.d.ts.map +1 -0
  50. package/src/core/bvh8/build/bvh8_build_for_geometry.js +303 -0
  51. package/src/core/bvh8/build/bvh8_from_proxy.d.ts +9 -0
  52. package/src/core/bvh8/build/bvh8_from_proxy.d.ts.map +1 -0
  53. package/src/core/bvh8/build/bvh8_from_proxy.js +256 -0
  54. package/src/core/bvh8/build/byte.d.ts +7 -0
  55. package/src/core/bvh8/build/byte.d.ts.map +1 -0
  56. package/src/core/bvh8/build/byte.js +10 -0
  57. package/src/core/bvh8/build/encode_bounds_e.d.ts +9 -0
  58. package/src/core/bvh8/build/encode_bounds_e.d.ts.map +1 -0
  59. package/src/core/bvh8/build/encode_bounds_e.js +12 -0
  60. package/src/core/bvh8/bvh8_convert_to_dot.d.ts +11 -0
  61. package/src/core/bvh8/bvh8_convert_to_dot.d.ts.map +1 -0
  62. package/src/core/bvh8/bvh8_convert_to_dot.js +133 -0
  63. package/src/core/bvh8/bvh8_count_primitives.d.ts +22 -0
  64. package/src/core/bvh8/bvh8_count_primitives.d.ts.map +1 -0
  65. package/src/core/bvh8/bvh8_count_primitives.js +98 -0
  66. package/src/core/bvh8/bvh8_geometry_validate.d.ts +16 -0
  67. package/src/core/bvh8/bvh8_geometry_validate.d.ts.map +1 -0
  68. package/src/core/bvh8/bvh8_geometry_validate.js +149 -0
  69. package/src/core/bvh8/bvh8_geometry_validate_indirect.d.ts +16 -0
  70. package/src/core/bvh8/bvh8_geometry_validate_indirect.d.ts.map +1 -0
  71. package/src/core/bvh8/bvh8_geometry_validate_indirect.js +177 -0
  72. package/src/core/bvh8/bvh8_get_node_bounds.d.ts +9 -0
  73. package/src/core/bvh8/bvh8_get_node_bounds.d.ts.map +1 -0
  74. package/src/core/bvh8/bvh8_get_node_bounds.js +35 -0
  75. package/src/core/bvh8/bvh8_get_node_child_bounds.d.ts +10 -0
  76. package/src/core/bvh8/bvh8_get_node_child_bounds.d.ts.map +1 -0
  77. package/src/core/bvh8/bvh8_get_node_child_bounds.js +53 -0
  78. package/src/core/bvh8/bvh8_node_child_surface_area.d.ts +9 -0
  79. package/src/core/bvh8/bvh8_node_child_surface_area.d.ts.map +1 -0
  80. package/src/core/bvh8/bvh8_node_child_surface_area.js +18 -0
  81. package/src/core/bvh8/bvh8_node_count_triangles.d.ts +8 -0
  82. package/src/core/bvh8/bvh8_node_count_triangles.d.ts.map +1 -0
  83. package/src/core/bvh8/bvh8_node_count_triangles.js +28 -0
  84. package/src/core/bvh8/bvh8_quality.d.ts +8 -0
  85. package/src/core/bvh8/bvh8_quality.d.ts.map +1 -0
  86. package/src/core/bvh8/bvh8_quality.js +73 -0
  87. package/src/core/bvh8/bvh8_validate_structure.d.ts +15 -0
  88. package/src/core/bvh8/bvh8_validate_structure.d.ts.map +1 -0
  89. package/src/core/bvh8/bvh8_validate_structure.js +87 -0
  90. package/src/core/collection/Uint32MinHeap.d.ts +56 -0
  91. package/src/core/collection/Uint32MinHeap.d.ts.map +1 -0
  92. package/src/core/collection/Uint32MinHeap.js +109 -0
  93. package/src/core/collection/list/FilteredListProjection.js +1 -1
  94. package/src/{engine/physics/island → core/collection/union-find}/union_find.d.ts +8 -5
  95. package/src/core/collection/union-find/union_find.d.ts.map +1 -0
  96. package/src/{engine/physics/island → core/collection/union-find}/union_find.js +8 -5
  97. package/src/core/dom/isImageBitmap.d.ts +7 -0
  98. package/src/core/dom/isImageBitmap.d.ts.map +1 -0
  99. package/src/core/dom/isImageBitmap.js +12 -0
  100. package/src/core/function/frameThrottle.d.ts +8 -0
  101. package/src/core/function/frameThrottle.d.ts.map +1 -0
  102. package/src/core/function/frameThrottle.js +23 -0
  103. package/src/{engine/physics/narrowphase/clip_against_axis_uv.d.ts → core/geom/2d/polygon/polygon2_clip_axis_halfplane.d.ts} +3 -3
  104. package/src/core/geom/2d/polygon/polygon2_clip_axis_halfplane.d.ts.map +1 -0
  105. package/src/{engine/physics/narrowphase/clip_against_axis_uv.js → core/geom/2d/polygon/polygon2_clip_axis_halfplane.js} +51 -51
  106. package/src/{engine/physics/narrowphase/decomposition/aabb_world_to_local.d.ts → core/geom/3d/aabb/aabb3_transform_oriented_inverse.d.ts} +9 -7
  107. package/src/core/geom/3d/aabb/aabb3_transform_oriented_inverse.d.ts.map +1 -0
  108. package/src/{engine/physics/narrowphase/decomposition/aabb_world_to_local.js → core/geom/3d/aabb/aabb3_transform_oriented_inverse.js} +9 -7
  109. package/src/core/geom/3d/aabb/compute_triangle_group_aabb3.d.ts +12 -0
  110. package/src/core/geom/3d/aabb/compute_triangle_group_aabb3.d.ts.map +1 -0
  111. package/src/core/geom/3d/aabb/compute_triangle_group_aabb3.js +46 -0
  112. package/src/core/geom/3d/box/box3_projected_half_extent.d.ts +28 -0
  113. package/src/core/geom/3d/box/box3_projected_half_extent.d.ts.map +1 -0
  114. package/src/core/geom/3d/box/box3_projected_half_extent.js +35 -0
  115. package/src/core/geom/3d/frustum/read_cluster_frustum_corners.js +1 -1
  116. package/src/core/geom/3d/frustum/read_frustum_corner.d.ts +9 -0
  117. package/src/core/geom/3d/frustum/read_frustum_corner.d.ts.map +1 -0
  118. package/src/core/geom/3d/frustum/read_frustum_corner.js +14 -0
  119. package/src/core/geom/3d/gjk/gjk.d.ts.map +1 -0
  120. package/src/{engine/physics → core/geom/3d}/gjk/gjk.js +430 -372
  121. package/src/{engine/physics → core/geom/3d}/gjk/gjk_epa_penetration.d.ts +8 -5
  122. package/src/core/geom/3d/gjk/gjk_epa_penetration.d.ts.map +1 -0
  123. package/src/{engine/physics → core/geom/3d}/gjk/gjk_epa_penetration.js +520 -544
  124. package/src/{engine/physics → core/geom/3d}/gjk/minkowski_support.d.ts +5 -4
  125. package/src/core/geom/3d/gjk/minkowski_support.d.ts.map +1 -0
  126. package/src/{engine/physics → core/geom/3d}/gjk/minkowski_support.js +71 -70
  127. package/src/{engine/physics → core/geom/3d}/gjk/mpr.d.ts +3 -3
  128. package/src/core/geom/3d/gjk/mpr.d.ts.map +1 -0
  129. package/src/{engine/physics → core/geom/3d}/gjk/mpr.js +368 -362
  130. package/src/{engine/physics/integration/quat_integrate.d.ts → core/geom/3d/quaternion/quat3_integrate.d.ts} +2 -2
  131. package/src/core/geom/3d/quaternion/quat3_integrate.d.ts.map +1 -0
  132. package/src/{engine/physics/integration/quat_integrate.js → core/geom/3d/quaternion/quat3_integrate.js} +1 -1
  133. package/src/{engine/physics/narrowphase/PosedShape.d.ts → core/geom/3d/shape/PosedShape3D.d.ts} +9 -8
  134. package/src/{engine/physics/narrowphase/PosedShape.d.ts.map → core/geom/3d/shape/PosedShape3D.d.ts.map} +1 -1
  135. package/src/{engine/physics/narrowphase/PosedShape.js → core/geom/3d/shape/PosedShape3D.js} +10 -9
  136. package/src/core/geom/3d/shape/TransformedShape3D.d.ts.map +1 -1
  137. package/src/core/geom/3d/shape/TransformedShape3D.js +15 -11
  138. package/src/core/geom/vec3/v3_quat3_apply_inverse.d.ts +1 -1
  139. package/src/core/geom/vec3/v3_quat3_apply_inverse.js +1 -1
  140. package/src/core/math/complex/complex_add.d.ts +1 -1
  141. package/src/core/math/complex/complex_add.d.ts.map +1 -1
  142. package/src/core/math/complex/complex_add.js +12 -3
  143. package/src/core/math/complex/complex_div.d.ts +1 -1
  144. package/src/core/math/complex/complex_div.d.ts.map +1 -1
  145. package/src/core/math/complex/complex_div.js +11 -4
  146. package/src/core/math/complex/complex_mul.d.ts +1 -1
  147. package/src/core/math/complex/complex_mul.d.ts.map +1 -1
  148. package/src/core/math/complex/complex_mul.js +10 -3
  149. package/src/core/math/complex/complex_sub.d.ts +1 -1
  150. package/src/core/math/complex/complex_sub.d.ts.map +1 -1
  151. package/src/core/math/complex/complex_sub.js +12 -3
  152. package/src/{engine/physics/fluid/solver/optimal_sor_omega.d.ts → core/math/linalg/sor_optimal_omega.d.ts} +4 -3
  153. package/src/core/math/linalg/sor_optimal_omega.d.ts.map +1 -0
  154. package/src/{engine/physics/fluid/solver/optimal_sor_omega.js → core/math/linalg/sor_optimal_omega.js} +4 -3
  155. package/src/core/math/lookup/ParameterLookupTable.d.ts +123 -0
  156. package/src/core/math/lookup/ParameterLookupTable.d.ts.map +1 -0
  157. package/src/core/math/lookup/ParameterLookupTable.js +495 -0
  158. package/src/core/math/lookup/ParameterLookupTableFlags.d.ts +5 -0
  159. package/src/core/math/lookup/ParameterLookupTableFlags.d.ts.map +1 -0
  160. package/src/core/math/lookup/ParameterLookupTableFlags.js +6 -0
  161. package/src/core/math/physics/kinematics/computeInterceptPoint.d.ts.map +1 -0
  162. package/src/{engine/physics → core/math/physics/kinematics}/computeInterceptPoint.js +79 -79
  163. package/src/core/math/physics/mie/ri_air.d.ts.map +1 -1
  164. package/src/core/math/physics/mie/ri_air.js +1 -3
  165. package/src/core/math/physics/mie/ri_ammonium_sulfate.d.ts.map +1 -1
  166. package/src/core/math/physics/mie/ri_ammonium_sulfate.js +1 -3
  167. package/src/core/math/physics/mie/ri_brine.d.ts.map +1 -1
  168. package/src/core/math/physics/mie/ri_brine.js +1 -3
  169. package/src/core/math/physics/mie/ri_dust.d.ts.map +1 -1
  170. package/src/core/math/physics/mie/ri_dust.js +1 -3
  171. package/src/core/math/physics/mie/ri_pollen.d.ts.map +1 -1
  172. package/src/core/math/physics/mie/ri_pollen.js +1 -3
  173. package/src/core/math/physics/mie/ri_smoke.d.ts.map +1 -1
  174. package/src/core/math/physics/mie/ri_smoke.js +1 -3
  175. package/src/core/math/physics/mie/ri_soot.d.ts.map +1 -1
  176. package/src/core/math/physics/mie/ri_soot.js +1 -3
  177. package/src/core/math/physics/mie/ri_water.d.ts.map +1 -1
  178. package/src/core/math/physics/mie/ri_water.js +1 -3
  179. package/src/core/math/random/random_pick_weighted_index.d.ts +10 -0
  180. package/src/core/math/random/random_pick_weighted_index.d.ts.map +1 -0
  181. package/src/core/math/random/random_pick_weighted_index.js +26 -0
  182. package/src/core/model/node-graph/NodeGraph.d.ts +9 -0
  183. package/src/core/model/node-graph/NodeGraph.d.ts.map +1 -1
  184. package/src/core/model/node-graph/NodeGraph.js +38 -0
  185. package/src/core/model/node-graph/visual/NodeGraphVisualData.d.ts +23 -0
  186. package/src/core/model/node-graph/visual/NodeGraphVisualData.d.ts.map +1 -1
  187. package/src/core/model/node-graph/visual/NodeGraphVisualData.js +54 -0
  188. package/src/core/path/convertPathToURL.d.ts +9 -0
  189. package/src/core/path/convertPathToURL.d.ts.map +1 -0
  190. package/src/core/path/convertPathToURL.js +107 -0
  191. package/src/core/process/worker/WorkerBuilder.js +1 -1
  192. package/src/core/process/worker/extractTransferables.js +1 -1
  193. package/src/engine/animation/curve/draw/build_tangent_editor.d.ts.map +1 -1
  194. package/src/engine/animation/curve/draw/build_tangent_editor.js +8 -1
  195. package/src/engine/animation/curve/editor/createKeyframeDraggableAspect.d.ts.map +1 -1
  196. package/src/engine/animation/curve/editor/createKeyframeDraggableAspect.js +11 -5
  197. package/src/engine/asset/Asset.d.ts.map +1 -1
  198. package/src/engine/asset/Asset.js +16 -6
  199. package/src/engine/asset/AssetManager.d.ts +61 -52
  200. package/src/engine/asset/AssetManager.d.ts.map +1 -1
  201. package/src/engine/asset/AssetManager.js +1411 -1045
  202. package/src/engine/asset/AssetRequest.d.ts +1 -1
  203. package/src/engine/asset/AssetRequest.d.ts.map +1 -1
  204. package/src/engine/asset/AssetRequest.js +1 -1
  205. package/src/engine/asset/AssetRequestScope.d.ts.map +1 -1
  206. package/src/engine/asset/AssetRequestScope.js +7 -0
  207. package/src/engine/asset/PendingAsset.d.ts +32 -1
  208. package/src/engine/asset/PendingAsset.d.ts.map +1 -1
  209. package/src/engine/asset/PendingAsset.js +108 -61
  210. package/src/engine/asset/loaders/ArrayBufferLoader.js +2 -2
  211. package/src/engine/asset/loaders/AssetLoader.d.ts.map +1 -1
  212. package/src/engine/asset/loaders/AssetLoader.js +19 -2
  213. package/src/engine/asset/loaders/GLTFAssetLoader.d.ts.map +1 -1
  214. package/src/engine/asset/loaders/GLTFAssetLoader.js +123 -114
  215. package/src/engine/asset/loaders/JavascriptAssetLoader.d.ts +1 -1
  216. package/src/engine/asset/loaders/JavascriptAssetLoader.d.ts.map +1 -1
  217. package/src/engine/asset/loaders/JavascriptAssetLoader.js +31 -47
  218. package/src/engine/asset/loaders/JsonAssetLoader.js +1 -1
  219. package/src/engine/asset/loaders/SVGAssetLoader.js +2 -2
  220. package/src/engine/asset/loaders/SoundAssetLoader.js +1 -1
  221. package/src/engine/asset/loaders/TextAssetLoader.js +2 -2
  222. package/src/{core → engine/asset/loaders}/font/FontAsset.d.ts +1 -1
  223. package/src/engine/asset/loaders/font/FontAsset.d.ts.map +1 -0
  224. package/src/{core → engine/asset/loaders}/font/FontAsset.js +21 -21
  225. package/src/{core → engine/asset/loaders}/font/FontAssetLoader.d.ts +1 -1
  226. package/src/engine/asset/loaders/font/FontAssetLoader.d.ts.map +1 -0
  227. package/src/{core → engine/asset/loaders}/font/FontAssetLoader.js +20 -20
  228. package/src/engine/asset/loaders/image/ImageRGBADataLoader.d.ts +1 -1
  229. package/src/engine/asset/loaders/image/ImageRGBADataLoader.d.ts.map +1 -1
  230. package/src/engine/asset/loaders/image/ImageRGBADataLoader.js +11 -20
  231. package/src/engine/asset/loaders/texture/TextureAssetLoader.d.ts.map +1 -1
  232. package/src/engine/asset/loaders/texture/TextureAssetLoader.js +8 -2
  233. package/src/engine/asset/preloader/AssetPreloader.js +1 -1
  234. package/src/engine/ecs/sockets/serialization/AttachmentSocketsAssetLoader.d.ts +1 -1
  235. package/src/engine/ecs/sockets/serialization/AttachmentSocketsAssetLoader.d.ts.map +1 -1
  236. package/src/engine/ecs/sockets/serialization/AttachmentSocketsAssetLoader.js +19 -22
  237. package/src/engine/graphics/FrameThrottle.d.ts +1 -7
  238. package/src/engine/graphics/FrameThrottle.d.ts.map +1 -1
  239. package/src/engine/graphics/FrameThrottle.js +2 -24
  240. package/src/{core/geom/3d/shape/util → engine/graphics/debug}/shape_to_visual_entity.d.ts +1 -1
  241. package/src/engine/graphics/debug/shape_to_visual_entity.d.ts.map +1 -0
  242. package/src/{core/geom/3d/shape/util → engine/graphics/debug}/shape_to_visual_entity.js +159 -159
  243. package/src/{core/geom/3d/tetrahedra → engine/graphics/debug}/visualize_tetrahedral_mesh.d.ts +1 -1
  244. package/src/engine/graphics/debug/visualize_tetrahedral_mesh.d.ts.map +1 -0
  245. package/src/{core/geom/3d/tetrahedra → engine/graphics/debug}/visualize_tetrahedral_mesh.js +46 -46
  246. package/src/engine/graphics/ecs/animation/animator/graph/definition/serialization/AnimationGraphDefinitionAssetLoader.d.ts +1 -1
  247. package/src/engine/graphics/ecs/animation/animator/graph/definition/serialization/AnimationGraphDefinitionAssetLoader.d.ts.map +1 -1
  248. package/src/engine/graphics/ecs/animation/animator/graph/definition/serialization/AnimationGraphDefinitionAssetLoader.js +22 -32
  249. package/src/engine/graphics/particles/particular/engine/emitter/serde/ParameterLookupTableSerializationAdapter.d.ts.map +1 -1
  250. package/src/engine/graphics/particles/particular/engine/emitter/serde/ParameterLookupTableSerializationAdapter.js +2 -76
  251. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.d.ts.map +1 -1
  252. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.js +2 -427
  253. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTableFlags.d.ts +1 -4
  254. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTableFlags.d.ts.map +1 -1
  255. package/src/engine/graphics/particles/particular/engine/parameter/ParameterLookupTableFlags.js +2 -6
  256. package/src/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +1 -1
  257. package/src/engine/graphics/render/forward_plus/read_frustum_corner.d.ts +1 -8
  258. package/src/engine/graphics/render/forward_plus/read_frustum_corner.d.ts.map +1 -1
  259. package/src/engine/graphics/render/forward_plus/read_frustum_corner.js +2 -14
  260. package/src/engine/graphics/sh3/path_tracer/geometry/compute_triangle_group_aabb3.d.ts +1 -11
  261. package/src/engine/graphics/sh3/path_tracer/geometry/compute_triangle_group_aabb3.d.ts.map +1 -1
  262. package/src/engine/graphics/sh3/path_tracer/geometry/compute_triangle_group_aabb3.js +2 -46
  263. package/src/engine/graphics/sh3/prototypeSH3Probe.js +1 -1
  264. package/src/engine/graphics/texture/3d/scs3d_sample_linear3.d.ts +27 -0
  265. package/src/engine/graphics/texture/3d/scs3d_sample_linear3.d.ts.map +1 -0
  266. package/src/engine/graphics/texture/3d/scs3d_sample_linear3.js +81 -0
  267. package/src/engine/graphics/texture/isImageBitmap.d.ts +1 -6
  268. package/src/engine/graphics/texture/isImageBitmap.d.ts.map +1 -1
  269. package/src/engine/graphics/texture/isImageBitmap.js +2 -12
  270. package/src/{core/process/action → engine/intelligence/behavior/util}/AsynchronousDelayAction.d.ts +2 -2
  271. package/src/engine/intelligence/behavior/util/AsynchronousDelayAction.d.ts.map +1 -0
  272. package/src/{core/process/action → engine/intelligence/behavior/util}/AsynchronousDelayAction.js +55 -55
  273. package/src/engine/network/NetworkSession.d.ts +12 -1
  274. package/src/engine/network/NetworkSession.d.ts.map +1 -1
  275. package/src/engine/network/NetworkSession.js +52 -1
  276. package/src/engine/network/README.md +45 -0
  277. package/src/engine/network/convertPathToURL.d.ts +1 -8
  278. package/src/engine/network/convertPathToURL.d.ts.map +1 -1
  279. package/src/engine/network/convertPathToURL.js +2 -107
  280. package/src/engine/network/core/quantize/quantize_float.d.ts.map +1 -1
  281. package/src/engine/network/core/quantize/quantize_float.js +7 -0
  282. package/src/engine/network/core/quantize/quantize_position.d.ts.map +1 -1
  283. package/src/engine/network/core/quantize/quantize_position.js +12 -1
  284. package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
  285. package/src/engine/network/orchestrator/NetworkPeer.js +15 -1
  286. package/src/engine/network/replication/Replicator.d.ts +8 -0
  287. package/src/engine/network/replication/Replicator.d.ts.map +1 -1
  288. package/src/engine/network/replication/Replicator.js +48 -0
  289. package/src/engine/network/transport/Channel.d.ts.map +1 -1
  290. package/src/engine/network/transport/Channel.js +46 -12
  291. package/src/engine/network/transport/ReliableCommandPipeline.d.ts +16 -0
  292. package/src/engine/network/transport/ReliableCommandPipeline.d.ts.map +1 -1
  293. package/src/engine/network/transport/ReliableCommandPipeline.js +29 -0
  294. package/src/engine/network/transport/adapters/NodeUDPTransport.d.ts.map +1 -1
  295. package/src/engine/network/transport/adapters/NodeUDPTransport.js +7 -1
  296. package/src/engine/network/transport/fragments/packet_size.d.ts +5 -5
  297. package/src/engine/network/transport/fragments/packet_size.d.ts.map +1 -1
  298. package/src/engine/network/transport/fragments/packet_size.js +5 -5
  299. package/src/engine/physics/BULLET_REVIEW.md +1 -1
  300. package/src/engine/physics/JOLT_REVIEW.md +2 -2
  301. package/src/engine/physics/PLAN.md +1094 -945
  302. package/src/engine/physics/RAPIER_REVIEW.md +2 -2
  303. package/src/engine/physics/body/BodyStorage.d.ts +2 -12
  304. package/src/engine/physics/body/BodyStorage.d.ts.map +1 -1
  305. package/src/engine/physics/body/BodyStorage.js +406 -452
  306. package/src/engine/physics/body/SolverBodyState.d.ts.map +1 -1
  307. package/src/engine/physics/body/SolverBodyState.js +12 -3
  308. package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts +28 -3
  309. package/src/engine/physics/broadphase/compute_fat_world_aabb.d.ts.map +1 -1
  310. package/src/engine/physics/broadphase/compute_fat_world_aabb.js +60 -24
  311. package/src/engine/physics/broadphase/generate_pairs.d.ts +9 -5
  312. package/src/engine/physics/broadphase/generate_pairs.d.ts.map +1 -1
  313. package/src/engine/physics/broadphase/generate_pairs.js +52 -37
  314. package/src/engine/physics/ccd/linear_sweep.d.ts +15 -5
  315. package/src/engine/physics/ccd/linear_sweep.d.ts.map +1 -1
  316. package/src/engine/physics/ccd/linear_sweep.js +122 -40
  317. package/src/engine/physics/constraint/solve_constraints.d.ts.map +1 -1
  318. package/src/engine/physics/constraint/solve_constraints.js +830 -805
  319. package/src/engine/physics/contact/ManifoldStore.d.ts +91 -16
  320. package/src/engine/physics/contact/ManifoldStore.d.ts.map +1 -1
  321. package/src/engine/physics/contact/ManifoldStore.js +204 -60
  322. package/src/engine/physics/ecs/BodyKind.d.ts +7 -3
  323. package/src/engine/physics/ecs/BodyKind.d.ts.map +1 -1
  324. package/src/engine/physics/ecs/BodyKind.js +29 -25
  325. package/src/engine/physics/ecs/Collider.d.ts +7 -0
  326. package/src/engine/physics/ecs/Collider.d.ts.map +1 -1
  327. package/src/engine/physics/ecs/Collider.js +7 -0
  328. package/src/engine/physics/ecs/ColliderSerializationAdapter.js +1 -1
  329. package/src/engine/physics/ecs/PhysicsSystem.d.ts +110 -6
  330. package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
  331. package/src/engine/physics/ecs/PhysicsSystem.js +467 -45
  332. package/src/engine/physics/ecs/RigidBody.d.ts +20 -5
  333. package/src/engine/physics/ecs/RigidBody.d.ts.map +1 -1
  334. package/src/engine/physics/ecs/RigidBody.js +307 -286
  335. package/src/engine/physics/ecs/RigidBodyFlags.d.ts +6 -3
  336. package/src/engine/physics/ecs/RigidBodyFlags.d.ts.map +1 -1
  337. package/src/engine/physics/ecs/RigidBodyFlags.js +31 -28
  338. package/src/engine/physics/ecs/RigidBodySerializationAdapter.d.ts +12 -4
  339. package/src/engine/physics/ecs/RigidBodySerializationAdapter.d.ts.map +1 -1
  340. package/src/engine/physics/ecs/RigidBodySerializationAdapter.js +19 -5
  341. package/src/engine/physics/ecs/RigidBodySerializationUpgrader_0_1.d.ts +10 -0
  342. package/src/engine/physics/ecs/RigidBodySerializationUpgrader_0_1.d.ts.map +1 -0
  343. package/src/engine/physics/ecs/RigidBodySerializationUpgrader_0_1.js +37 -0
  344. package/src/engine/physics/ecs/find_non_finite_physics_state.d.ts +28 -0
  345. package/src/engine/physics/ecs/find_non_finite_physics_state.d.ts.map +1 -0
  346. package/src/engine/physics/ecs/find_non_finite_physics_state.js +76 -0
  347. package/src/engine/physics/events/ContactEventBuffer.d.ts +11 -0
  348. package/src/engine/physics/events/ContactEventBuffer.d.ts.map +1 -1
  349. package/src/engine/physics/events/ContactEventBuffer.js +40 -0
  350. package/src/engine/physics/events/diff_manifolds.d.ts +30 -13
  351. package/src/engine/physics/events/diff_manifolds.d.ts.map +1 -1
  352. package/src/engine/physics/events/diff_manifolds.js +87 -50
  353. package/src/engine/physics/fluid/FluidField.d.ts +45 -17
  354. package/src/engine/physics/fluid/FluidField.d.ts.map +1 -1
  355. package/src/engine/physics/fluid/FluidField.js +53 -23
  356. package/src/engine/physics/fluid/FluidSimulator.d.ts +141 -5
  357. package/src/engine/physics/fluid/FluidSimulator.d.ts.map +1 -1
  358. package/src/engine/physics/fluid/FluidSimulator.js +336 -43
  359. package/src/engine/physics/fluid/REVIEW_02_PLAN.md +114 -0
  360. package/src/engine/physics/fluid/ecs/FluidComponent.d.ts +4 -3
  361. package/src/engine/physics/fluid/ecs/FluidComponent.d.ts.map +1 -1
  362. package/src/engine/physics/fluid/ecs/FluidComponent.js +4 -3
  363. package/src/engine/physics/fluid/ecs/FluidSystem.d.ts +3 -3
  364. package/src/engine/physics/fluid/effector/AmbientWindFluidEffector.d.ts +41 -0
  365. package/src/engine/physics/fluid/effector/AmbientWindFluidEffector.d.ts.map +1 -0
  366. package/src/engine/physics/fluid/effector/AmbientWindFluidEffector.js +124 -0
  367. package/src/engine/physics/fluid/effector/WakeFluidEffector.d.ts +27 -8
  368. package/src/engine/physics/fluid/effector/WakeFluidEffector.d.ts.map +1 -1
  369. package/src/engine/physics/fluid/effector/WakeFluidEffector.js +67 -18
  370. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_scalar.d.ts +42 -0
  371. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_scalar.d.ts.map +1 -0
  372. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_scalar.js +136 -0
  373. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.d.ts +37 -0
  374. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.d.ts.map +1 -0
  375. package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.js +169 -0
  376. package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.d.ts +36 -0
  377. package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.d.ts.map +1 -0
  378. package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.js +100 -0
  379. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.d.ts +6 -0
  380. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.d.ts.map +1 -1
  381. package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.js +6 -0
  382. package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.d.ts +7 -2
  383. package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.d.ts.map +1 -1
  384. package/src/engine/physics/fluid/solver/v3_grid_apply_diffusion.js +17 -12
  385. package/src/engine/physics/fluid/solver/v3_grid_apply_vorticity_confinement.d.ts +42 -0
  386. package/src/engine/physics/fluid/solver/v3_grid_apply_vorticity_confinement.d.ts.map +1 -0
  387. package/src/engine/physics/fluid/solver/v3_grid_apply_vorticity_confinement.js +131 -0
  388. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.d.ts +32 -22
  389. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.d.ts.map +1 -1
  390. package/src/engine/physics/fluid/solver/v3_grid_compute_solid_neighbour_mask.js +43 -26
  391. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_constant.d.ts +31 -0
  392. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_constant.d.ts.map +1 -0
  393. package/src/engine/physics/fluid/solver/v3_grid_patch_edges_constant.js +77 -0
  394. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.d.ts +26 -19
  395. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.d.ts.map +1 -1
  396. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure.js +46 -42
  397. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.d.ts +38 -10
  398. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.d.ts.map +1 -1
  399. package/src/engine/physics/fluid/solver/v3_grid_solve_pressure_pcg.js +158 -75
  400. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts +22 -17
  401. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts.map +1 -1
  402. package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.js +108 -96
  403. package/src/engine/physics/inertia/world_inverse_inertia.d.ts +30 -1
  404. package/src/engine/physics/inertia/world_inverse_inertia.d.ts.map +1 -1
  405. package/src/engine/physics/inertia/world_inverse_inertia.js +160 -116
  406. package/src/engine/physics/integration/integrate_position.js +97 -97
  407. package/src/engine/physics/island/IslandBuilder.d.ts +49 -8
  408. package/src/engine/physics/island/IslandBuilder.d.ts.map +1 -1
  409. package/src/engine/physics/island/IslandBuilder.js +93 -14
  410. package/src/engine/physics/narrowphase/box_box_manifold.d.ts.map +1 -1
  411. package/src/engine/physics/narrowphase/box_box_manifold.js +683 -673
  412. package/src/engine/physics/narrowphase/box_triangle_contact.d.ts.map +1 -1
  413. package/src/engine/physics/narrowphase/box_triangle_contact.js +899 -749
  414. package/src/engine/physics/narrowphase/capsule_contacts.d.ts +27 -0
  415. package/src/engine/physics/narrowphase/capsule_contacts.d.ts.map +1 -1
  416. package/src/engine/physics/narrowphase/capsule_contacts.js +624 -459
  417. package/src/engine/physics/narrowphase/capsule_triangle_contact.d.ts.map +1 -1
  418. package/src/engine/physics/narrowphase/capsule_triangle_contact.js +58 -38
  419. package/src/engine/physics/narrowphase/compute_penetration.d.ts.map +1 -1
  420. package/src/engine/physics/narrowphase/compute_penetration.js +369 -325
  421. package/src/engine/physics/narrowphase/convex_convex_manifold.d.ts +3 -1
  422. package/src/engine/physics/narrowphase/convex_convex_manifold.d.ts.map +1 -1
  423. package/src/engine/physics/narrowphase/convex_convex_manifold.js +568 -422
  424. package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.d.ts +6 -3
  425. package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.d.ts.map +1 -1
  426. package/src/engine/physics/narrowphase/decomposition/heightmap_enumerate_triangles.js +66 -10
  427. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts +4 -1
  428. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.d.ts.map +1 -1
  429. package/src/engine/physics/narrowphase/decomposition/mesh_enumerate_triangles.js +97 -94
  430. package/src/engine/physics/narrowphase/mesh_mesh_tet_manifold.js +117 -117
  431. package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
  432. package/src/engine/physics/narrowphase/narrowphase_step.js +1738 -1739
  433. package/src/engine/physics/narrowphase/reduce_manifold_contacts.d.ts +14 -7
  434. package/src/engine/physics/narrowphase/reduce_manifold_contacts.d.ts.map +1 -1
  435. package/src/engine/physics/narrowphase/reduce_manifold_contacts.js +74 -69
  436. package/src/engine/physics/persistence/solver_caches.d.ts +20 -0
  437. package/src/engine/physics/persistence/solver_caches.d.ts.map +1 -0
  438. package/src/engine/physics/persistence/solver_caches.js +309 -0
  439. package/src/engine/physics/queries/overlap_shape.d.ts.map +1 -1
  440. package/src/engine/physics/queries/overlap_shape.js +187 -184
  441. package/src/engine/physics/queries/raycast.d.ts +3 -2
  442. package/src/engine/physics/queries/raycast.d.ts.map +1 -1
  443. package/src/engine/physics/queries/raycast.js +37 -11
  444. package/src/engine/physics/queries/shape_cast.d.ts +18 -5
  445. package/src/engine/physics/queries/shape_cast.d.ts.map +1 -1
  446. package/src/engine/physics/queries/shape_cast.js +417 -393
  447. package/src/engine/physics/solver/solve_contacts.d.ts +22 -6
  448. package/src/engine/physics/solver/solve_contacts.d.ts.map +1 -1
  449. package/src/engine/physics/solver/solve_contacts.js +1482 -1338
  450. package/src/engine/physics/vehicle/RaycastVehicle.d.ts.map +1 -1
  451. package/src/engine/physics/vehicle/RaycastVehicle.js +344 -339
  452. package/src/engine/ui/DraggableAspect.d.ts +12 -3
  453. package/src/engine/ui/DraggableAspect.d.ts.map +1 -1
  454. package/src/engine/ui/DraggableAspect.js +115 -83
  455. package/src/generation/COORDINATES.md +54 -0
  456. package/src/generation/GridTaskGroup.js +2 -2
  457. package/src/generation/REVIEW_01_ACTION_PLAN.md +628 -0
  458. package/src/generation/automata/CaveGeneratorCellularAutomata.d.ts +9 -1
  459. package/src/generation/automata/CaveGeneratorCellularAutomata.d.ts.map +1 -1
  460. package/src/generation/automata/CaveGeneratorCellularAutomata.js +79 -59
  461. package/src/generation/automata/CellularAutomata.d.ts +6 -3
  462. package/src/generation/automata/CellularAutomata.d.ts.map +1 -1
  463. package/src/generation/automata/CellularAutomata.js +22 -19
  464. package/src/generation/filtering/CellFilter.d.ts +17 -0
  465. package/src/generation/filtering/CellFilter.d.ts.map +1 -1
  466. package/src/generation/filtering/CellFilter.js +117 -77
  467. package/src/generation/filtering/CellFilterCellMatcher.d.ts.map +1 -1
  468. package/src/generation/filtering/CellFilterCellMatcher.js +2 -0
  469. package/src/generation/filtering/boolean/CellFilterLiteralBoolean.d.ts +5 -0
  470. package/src/generation/filtering/boolean/CellFilterLiteralBoolean.d.ts.map +1 -1
  471. package/src/generation/filtering/boolean/CellFilterLiteralBoolean.js +15 -0
  472. package/src/generation/filtering/core/CellFilterBinaryOperation.d.ts +0 -1
  473. package/src/generation/filtering/core/CellFilterBinaryOperation.d.ts.map +1 -1
  474. package/src/generation/filtering/core/CellFilterBinaryOperation.js +37 -50
  475. package/src/generation/filtering/core/CellFilterOperationTertiary.d.ts +0 -1
  476. package/src/generation/filtering/core/CellFilterOperationTertiary.d.ts.map +1 -1
  477. package/src/generation/filtering/core/CellFilterOperationTertiary.js +43 -59
  478. package/src/generation/filtering/core/CellFilterUnaryOperation.d.ts +0 -1
  479. package/src/generation/filtering/core/CellFilterUnaryOperation.d.ts.map +1 -1
  480. package/src/generation/filtering/core/CellFilterUnaryOperation.js +29 -33
  481. package/src/generation/filtering/numeric/CellFilterCache.d.ts +1 -0
  482. package/src/generation/filtering/numeric/CellFilterCache.d.ts.map +1 -1
  483. package/src/generation/filtering/numeric/complex/CellFilterAngleToNormal.d.ts +3 -2
  484. package/src/generation/filtering/numeric/complex/CellFilterAngleToNormal.d.ts.map +1 -1
  485. package/src/generation/filtering/numeric/complex/CellFilterAngleToNormal.js +9 -35
  486. package/src/generation/filtering/numeric/complex/CellFilterCurvature.d.ts +0 -1
  487. package/src/generation/filtering/numeric/complex/CellFilterCurvature.d.ts.map +1 -1
  488. package/src/generation/filtering/numeric/complex/CellFilterCurvature.js +19 -43
  489. package/src/generation/filtering/numeric/complex/CellFilterFXAA.d.ts +0 -1
  490. package/src/generation/filtering/numeric/complex/CellFilterFXAA.d.ts.map +1 -1
  491. package/src/generation/filtering/numeric/complex/CellFilterFXAA.js +2 -6
  492. package/src/generation/filtering/numeric/complex/CellFilterGaussianBlur.d.ts.map +1 -1
  493. package/src/generation/filtering/numeric/complex/CellFilterGaussianBlur.js +9 -12
  494. package/src/generation/filtering/numeric/complex/CellFilterSimplexNoise.d.ts.map +1 -1
  495. package/src/generation/filtering/numeric/complex/CellFilterSimplexNoise.js +2 -1
  496. package/src/generation/filtering/numeric/complex/CellFilterSobel.d.ts +0 -1
  497. package/src/generation/filtering/numeric/complex/CellFilterSobel.d.ts.map +1 -1
  498. package/src/generation/filtering/numeric/complex/CellFilterSobel.js +2 -6
  499. package/src/generation/filtering/numeric/math/CellFilterInverseLerp.d.ts +5 -4
  500. package/src/generation/filtering/numeric/math/CellFilterInverseLerp.d.ts.map +1 -1
  501. package/src/generation/filtering/numeric/math/CellFilterInverseLerp.js +5 -4
  502. package/src/generation/filtering/numeric/process/computeFilterSurfaceNormal.d.ts +17 -0
  503. package/src/generation/filtering/numeric/process/computeFilterSurfaceNormal.d.ts.map +1 -0
  504. package/src/generation/filtering/numeric/process/computeFilterSurfaceNormal.js +42 -0
  505. package/src/generation/filtering/numeric/sampling/AbstractCellFilterSampleGridLayer.d.ts.map +1 -1
  506. package/src/generation/filtering/numeric/sampling/AbstractCellFilterSampleGridLayer.js +7 -1
  507. package/src/generation/filtering/numeric/util/populateSampler2DFromCellFilter.d.ts.map +1 -1
  508. package/src/generation/filtering/numeric/util/populateSampler2DFromCellFilter.js +7 -10
  509. package/src/generation/filtering/numeric/util/sampler_from_filter.d.ts.map +1 -1
  510. package/src/generation/filtering/numeric/util/sampler_from_filter.js +2 -1
  511. package/src/generation/grid/GridData.d.ts.map +1 -1
  512. package/src/generation/grid/GridData.js +14 -1
  513. package/src/generation/grid/actions/ContinuousGridCellAction.d.ts +10 -3
  514. package/src/generation/grid/actions/ContinuousGridCellAction.d.ts.map +1 -1
  515. package/src/generation/grid/actions/ContinuousGridCellAction.js +18 -3
  516. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainHeight.d.ts +11 -1
  517. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainHeight.d.ts.map +1 -1
  518. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainHeight.js +13 -3
  519. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainObstacle.d.ts +1 -1
  520. package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainObstacle.js +2 -2
  521. package/src/generation/grid/actions/ContinuousGridCellActionWriteObstacle.d.ts +1 -1
  522. package/src/generation/grid/actions/ContinuousGridCellActionWriteObstacle.d.ts.map +1 -1
  523. package/src/generation/grid/actions/ContinuousGridCellActionWriteObstacle.js +4 -6
  524. package/src/generation/grid/coords/grid_to_texel.d.ts +9 -0
  525. package/src/generation/grid/coords/grid_to_texel.d.ts.map +1 -0
  526. package/src/generation/grid/coords/grid_to_texel.js +10 -0
  527. package/src/generation/grid/coords/texel_to_grid.d.ts +9 -0
  528. package/src/generation/grid/coords/texel_to_grid.d.ts.map +1 -0
  529. package/src/generation/grid/coords/texel_to_grid.js +10 -0
  530. package/src/generation/grid/generation/GridTaskApplyActionToCells.d.ts +2 -2
  531. package/src/generation/grid/generation/GridTaskApplyActionToCells.d.ts.map +1 -1
  532. package/src/generation/grid/generation/GridTaskApplyActionToCells.js +10 -6
  533. package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.d.ts.map +1 -1
  534. package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.js +20 -21
  535. package/src/generation/grid/generation/GridTaskExecuteRuleTimes.d.ts +7 -0
  536. package/src/generation/grid/generation/GridTaskExecuteRuleTimes.d.ts.map +1 -1
  537. package/src/generation/grid/generation/GridTaskExecuteRuleTimes.js +18 -10
  538. package/src/generation/grid/generation/discrete/GridTaskCellularAutomata.d.ts.map +1 -1
  539. package/src/generation/grid/generation/discrete/GridTaskCellularAutomata.js +16 -7
  540. package/src/generation/grid/generation/discrete/GridTaskConnectRooms.d.ts +5 -3
  541. package/src/generation/grid/generation/discrete/GridTaskConnectRooms.d.ts.map +1 -1
  542. package/src/generation/grid/generation/discrete/GridTaskConnectRooms.js +26 -23
  543. package/src/generation/grid/generation/discrete/layer/GridTaskBuildSourceDistanceMap.d.ts.map +1 -1
  544. package/src/generation/grid/generation/discrete/layer/GridTaskBuildSourceDistanceMap.js +10 -1
  545. package/src/generation/grid/generation/grid/select/CellSupplierBestN.d.ts.map +1 -1
  546. package/src/generation/grid/generation/grid/select/CellSupplierBestN.js +4 -0
  547. package/src/generation/grid/generation/road/GridTaskGenerateRoads.d.ts +15 -8
  548. package/src/generation/grid/generation/road/GridTaskGenerateRoads.d.ts.map +1 -1
  549. package/src/generation/grid/generation/road/GridTaskGenerateRoads.js +89 -92
  550. package/src/generation/markers/GridActionRuleSet.d.ts.map +1 -1
  551. package/src/generation/markers/GridActionRuleSet.js +10 -2
  552. package/src/generation/markers/GridCellActionPlaceMarker.d.ts +11 -0
  553. package/src/generation/markers/GridCellActionPlaceMarker.d.ts.map +1 -1
  554. package/src/generation/markers/GridCellActionPlaceMarker.js +20 -3
  555. package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts +3 -1
  556. package/src/generation/markers/GridCellActionPlaceMarkerGroup.d.ts.map +1 -1
  557. package/src/generation/markers/GridCellActionPlaceMarkerGroup.js +9 -2
  558. package/src/generation/markers/MarkerNode.d.ts +8 -3
  559. package/src/generation/markers/MarkerNode.d.ts.map +1 -1
  560. package/src/generation/markers/MarkerNode.js +12 -5
  561. package/src/generation/markers/actions/MarkerNodeActionEntityPlacement.js +1 -1
  562. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessor.d.ts +1 -1
  563. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessor.d.ts.map +1 -1
  564. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessor.js +1 -1
  565. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorClingToTerrain.d.ts +1 -1
  566. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorClingToTerrain.d.ts.map +1 -1
  567. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorClingToTerrain.js +1 -1
  568. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorRandomRotation.d.ts +1 -1
  569. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorRandomRotation.d.ts.map +1 -1
  570. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorRandomRotation.js +2 -2
  571. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorSequence.d.ts +1 -1
  572. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorSequence.d.ts.map +1 -1
  573. package/src/generation/markers/actions/placement/MarkerNodeEntityProcessorSequence.js +2 -2
  574. package/src/generation/markers/actions/probability/MarkerNodeActionSelectWeighted.d.ts.map +1 -1
  575. package/src/generation/markers/actions/probability/MarkerNodeActionSelectWeighted.js +6 -4
  576. package/src/generation/markers/actions/probability/MarkerNodeActionWeightedElement.d.ts.map +1 -1
  577. package/src/generation/markers/actions/probability/MarkerNodeActionWeightedElement.js +1 -3
  578. package/src/generation/markers/actions/terrain/MarkerNodeActionPaintTerrain.d.ts.map +1 -1
  579. package/src/generation/markers/actions/terrain/MarkerNodeActionPaintTerrain.js +12 -11
  580. package/src/generation/markers/matcher/MarkerNodeMatcherAnd.js +2 -2
  581. package/src/generation/markers/transform/MarkerNodeTransformer.d.ts +4 -1
  582. package/src/generation/markers/transform/MarkerNodeTransformer.d.ts.map +1 -1
  583. package/src/generation/markers/transform/MarkerNodeTransformer.js +4 -1
  584. package/src/generation/markers/transform/MarkerNodeTransformerAddPositionYFromFilter.d.ts.map +1 -1
  585. package/src/generation/markers/transform/MarkerNodeTransformerAddPositionYFromFilter.js +1 -3
  586. package/src/generation/markers/transform/MarkerNodeTransformerOffsetPosition.d.ts +5 -0
  587. package/src/generation/markers/transform/MarkerNodeTransformerOffsetPosition.d.ts.map +1 -1
  588. package/src/generation/markers/transform/MarkerNodeTransformerOffsetPosition.js +15 -0
  589. package/src/generation/markers/transform/MarkerNodeTransformerRecordProperty.d.ts.map +1 -1
  590. package/src/generation/markers/transform/MarkerNodeTransformerRecordProperty.js +1 -3
  591. package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilter.d.ts.map +1 -1
  592. package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilter.js +2 -4
  593. package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilterGradient.d.ts.map +1 -1
  594. package/src/generation/markers/transform/MarkerNodeTransformerYRotateByFilterGradient.js +1 -3
  595. package/src/generation/placement/GridCellPlacementRule.d.ts.map +1 -1
  596. package/src/generation/placement/GridCellPlacementRule.js +1 -3
  597. package/src/generation/placement/action/GridCellActionWriteFilterToLayer.d.ts.map +1 -1
  598. package/src/generation/placement/action/GridCellActionWriteFilterToLayer.js +8 -10
  599. package/src/generation/placement/action/random/weighted/CellActionSelectWeightedRandom.d.ts.map +1 -1
  600. package/src/generation/placement/action/random/weighted/CellActionSelectWeightedRandom.js +6 -4
  601. package/src/generation/placement/action/random/weighted/WeightedGridCellAction.d.ts.map +1 -1
  602. package/src/generation/placement/action/random/weighted/WeightedGridCellAction.js +1 -3
  603. package/src/generation/rules/CellMatcher.d.ts +3 -1
  604. package/src/generation/rules/CellMatcher.d.ts.map +1 -1
  605. package/src/generation/rules/CellMatcher.js +3 -1
  606. package/src/generation/rules/CellMatcherFromFilter.d.ts.map +1 -1
  607. package/src/generation/rules/CellMatcherFromFilter.js +1 -3
  608. package/src/generation/rules/CellMatcherLayerBitMaskTest.d.ts.map +1 -1
  609. package/src/generation/rules/CellMatcherLayerBitMaskTest.js +6 -20
  610. package/src/generation/test_support/executeTaskTreeSync.d.ts +9 -0
  611. package/src/generation/test_support/executeTaskTreeSync.d.ts.map +1 -0
  612. package/src/generation/test_support/executeTaskTreeSync.js +78 -0
  613. package/src/generation/theme/TerrainLayerRuleAggregator.d.ts +2 -1
  614. package/src/generation/theme/TerrainLayerRuleAggregator.d.ts.map +1 -1
  615. package/src/generation/theme/TerrainLayerRuleAggregator.js +9 -6
  616. package/src/generation/theme/Theme.d.ts +1 -1
  617. package/src/generation/theme/Theme.d.ts.map +1 -1
  618. package/src/generation/theme/Theme.js +2 -2
  619. package/src/generation/theme/ThemeEngine.d.ts +3 -3
  620. package/src/generation/theme/ThemeEngine.d.ts.map +1 -1
  621. package/src/generation/theme/ThemeEngine.js +26 -16
  622. package/src/generation/theme/cell/CellProcessingRule.d.ts +3 -3
  623. package/src/generation/theme/cell/CellProcessingRule.d.ts.map +1 -1
  624. package/src/generation/theme/cell/CellProcessingRule.js +6 -10
  625. package/src/generation/theme/cell/CellProcessingRuleSet.d.ts +1 -1
  626. package/src/generation/theme/cell/CellProcessingRuleSet.d.ts.map +1 -1
  627. package/src/generation/theme/cell/CellProcessingRuleSet.js +2 -2
  628. package/src/view/common/ListView.js +1 -1
  629. package/src/view/elements/BottomLeftResizeHandleView.d.ts.map +1 -1
  630. package/src/view/elements/BottomLeftResizeHandleView.js +13 -5
  631. package/src/core/font/FontAsset.d.ts.map +0 -1
  632. package/src/core/font/FontAssetLoader.d.ts.map +0 -1
  633. package/src/core/geom/3d/shape/util/shape_to_visual_entity.d.ts.map +0 -1
  634. package/src/core/geom/3d/tetrahedra/visualize_tetrahedral_mesh.d.ts.map +0 -1
  635. package/src/core/process/action/AsynchronousDelayAction.d.ts.map +0 -1
  636. package/src/engine/physics/computeInterceptPoint.d.ts.map +0 -1
  637. package/src/engine/physics/fluid/solver/optimal_sor_omega.d.ts.map +0 -1
  638. package/src/engine/physics/gjk/gjk.d.ts.map +0 -1
  639. package/src/engine/physics/gjk/gjk_epa_penetration.d.ts.map +0 -1
  640. package/src/engine/physics/gjk/minkowski_support.d.ts.map +0 -1
  641. package/src/engine/physics/gjk/mpr.d.ts.map +0 -1
  642. package/src/engine/physics/integration/quat_integrate.d.ts.map +0 -1
  643. package/src/engine/physics/island/union_find.d.ts.map +0 -1
  644. package/src/engine/physics/narrowphase/clip_against_axis_uv.d.ts.map +0 -1
  645. package/src/engine/physics/narrowphase/decomposition/aabb_world_to_local.d.ts.map +0 -1
  646. package/src/generation/grid/generation/discrete/layer/GridTaskDistanceToMarkers.d.ts +0 -21
  647. package/src/generation/grid/generation/discrete/layer/GridTaskDistanceToMarkers.d.ts.map +0 -1
  648. package/src/generation/grid/generation/discrete/layer/GridTaskDistanceToMarkers.js +0 -68
  649. package/src/generation/grid/generation/grid/GridTaskGridAlignedNodeGenerator.d.ts +0 -10
  650. package/src/generation/grid/generation/grid/GridTaskGridAlignedNodeGenerator.d.ts.map +0 -1
  651. package/src/generation/grid/generation/grid/GridTaskGridAlignedNodeGenerator.js +0 -17
  652. /package/src/{engine/physics → core/geom/3d}/gjk/NOTES.md +0 -0
  653. /package/src/{engine/physics → core/geom/3d}/gjk/gjk.d.ts +0 -0
  654. /package/src/{engine/physics → core/math/physics/kinematics}/computeInterceptPoint.d.ts +0 -0
@@ -1,1045 +1,1411 @@
1
- import { assert } from "../../core/assert.js";
2
- import { array_push_if_unique } from "../../core/collection/array/array_push_if_unique.js";
3
- import { array_remove_first } from "../../core/collection/array/array_remove_first.js";
4
- import BinaryHeap from "../../core/collection/heap/BinaryHeap.js";
5
- import { HashMap } from "../../core/collection/map/HashMap.js";
6
- import { ObservedMap } from "../../core/collection/map/ObservedMap.js";
7
- import { Deque } from "../../core/collection/queue/Deque.js";
8
- import { HashSet } from "../../core/collection/set/HashSet.js";
9
- import { noop } from "../../core/function/noop.js";
10
- import ConcurrentExecutor from "../../core/process/executor/ConcurrentExecutor.js";
11
- import Task from "../../core/process/task/Task.js";
12
- import { TaskSignal } from "../../core/process/task/TaskSignal.js";
13
- import { AssetDescription } from "./AssetDescription.js";
14
- import { AssetLoadState } from "./AssetLoadState.js";
15
- import { AssetRequest, AssetRequestFlags } from "./AssetRequest.js";
16
- import { AssetRequestScope } from "./AssetRequestScope.js";
17
- import { CrossOriginConfig } from "./CORS/CrossOriginConfig.js";
18
- import { AssetLoader } from "./loaders/AssetLoader.js";
19
- import { PendingAsset } from "./PendingAsset.js";
20
- import { extractAssetListFromManager } from "./preloader/extractAssetListFromManager.js";
21
-
22
-
23
- class Response {
24
- /**
25
- *
26
- * @param {Asset} asset
27
- * @param {AssetRequest} request
28
- */
29
- constructor(asset, request) {
30
- this.asset = asset;
31
- this.request = request;
32
- }
33
- }
34
-
35
- /**
36
- * Used by the priority queue, so the priority is inverted as the BinaryHeap returns elements in ascending score order (from lowest)
37
- * @param {PendingAsset} pending_asset
38
- * @returns {number}
39
- */
40
- function get_pending_asset_priority_score(pending_asset) {
41
- return -pending_asset.priority;
42
- }
43
-
44
-
45
- // TODO handle 429 HTTP error gracefully
46
-
47
- /**
48
- * Handles loading/generating assets
49
- * @template CTX
50
- * @class
51
- */
52
- export class AssetManager {
53
- /**
54
- *
55
- * @type {HashMap<AssetDescription, Asset>}
56
- * @private
57
- */
58
- assets = new HashMap({
59
- capacity: 1024
60
- });
61
-
62
- /**
63
- *
64
- * @type {ObservedMap<AssetDescription, PendingAsset>}
65
- */
66
- request_map = new ObservedMap(new HashMap());
67
-
68
- /**
69
- * Waiting queue for assets that haven't yet been scheduled (passed to relevant loader)
70
- * @type {BinaryHeap<PendingAsset>}
71
- * @private
72
- */
73
- #pending_asset_wait_queue = new BinaryHeap(get_pending_asset_priority_score);
74
- /**
75
- * Assets currently being processed by #loaders
76
- * @type {Set<PendingAsset>}
77
- * @private
78
- */
79
- #pending_asset_active_load_set = new Set();
80
-
81
- /**
82
- * Maximum number of requests that can be handled at the same time
83
- * Since most of the requests are handled over the network, this can help you control network concurrency,
84
- * this can be useful to keep some network slots available for high-priority requests such as UI related ones
85
- * TODO currently nested asset requests are not recognized, so if nesting level exceeds concurrency - it will lead to a deadlock
86
- * @type {number}
87
- */
88
- load_concurrency = Infinity;
89
-
90
- /**
91
- * Registered asset loaders
92
- * @private
93
- * @type {Object<AssetLoader>}
94
- */
95
- #loaders = {};
96
-
97
- /**
98
- * After an asset is loaded, a chain of transforms can be applied to it, these are registered here
99
- * Transformers are executed in the order in which they are added
100
- * Identified by asset "type" string
101
- * @type {Object<AssetTransformer[]>}
102
- * @private
103
- */
104
- #transformers = {};
105
-
106
- /**
107
- * Named links to specific assets. Useful to later re-mapping assets and having meaningful names for them
108
- * @type {Map<string, AssetDescription>}
109
- * @private
110
- * @see resolveAlias
111
- * @see assignAlias
112
- * @see promiseByAlias
113
- */
114
- #aliases = new Map();
115
-
116
- /**
117
- * This will be added to asset path for actual network resolution
118
- * @type {string}
119
- * @private
120
- */
121
- rootPath = '';
122
-
123
- /**
124
- *
125
- * @type {CrossOriginConfig}
126
- */
127
- crossOriginConfig = new CrossOriginConfig();
128
-
129
- /**
130
- *
131
- * @type {HashSet<AssetDescription>}
132
- * @private
133
- */
134
- #failures = new HashSet();
135
-
136
- /**
137
- * Queue of responses that are waiting to be dispatched
138
- * @type {Deque<Response>}
139
- * @private
140
- */
141
- #response_queue = new Deque();
142
-
143
- /**
144
- *
145
- * @type {Task}
146
- * @private
147
- */
148
- #response_processor = new Task({
149
- name: "Asset Manager Response processor",
150
- cycleFunction: () => {
151
- if (this.#response_queue.isEmpty()) {
152
- return TaskSignal.Yield;
153
- }
154
-
155
- const response = this.#response_queue.removeFirst();
156
-
157
- this.#process_response(response);
158
-
159
- return TaskSignal.Continue;
160
- }
161
- });
162
-
163
- /**
164
- *
165
- * @type {boolean}
166
- * @private
167
- */
168
- #is_running = false;
169
-
170
- /**
171
- *
172
- * @type {CTX|null}
173
- * @private
174
- */
175
- #context = null;
176
-
177
- /**
178
- *
179
- * @type {ConcurrentExecutor|null}
180
- */
181
- #executor = null;
182
-
183
- /**
184
- *
185
- * @param {CTX} context
186
- * @param {ConcurrentExecutor} executor
187
- * @constructor
188
- */
189
- constructor({
190
- context,
191
- executor = new ConcurrentExecutor()
192
- } = {}) {
193
-
194
- this.#context = context;
195
- this.#executor = executor;
196
-
197
- }
198
-
199
- startup() {
200
- if (this.#is_running) {
201
- return;
202
- }
203
-
204
- this.#executor.run(this.#response_processor);
205
-
206
- this.#is_running = true;
207
- }
208
-
209
- /**
210
- *
211
- * @param {number} [immediate] should be let pending work finish, or abort it and shut down immediately? Defaults to false (wait)
212
- * @return {Promise<void>}
213
- */
214
- async shutdown(immediate = false) {
215
- if (!this.#is_running) {
216
- return;
217
- }
218
-
219
- if (!immediate) {
220
- // wait until all responses have been processed
221
- await Promise.allSettled([Task.promise(this.#response_processor)]);
222
- }
223
-
224
- this.#executor.removeTask(this.#response_processor);
225
-
226
- this.#is_running = false;
227
- }
228
-
229
- /**
230
- * Remove asset if it is loaded, does nothing otherwise
231
- * @param {String} path
232
- * @param {String} type
233
- * @returns {boolean} true if asset was removed, else otherwise
234
- */
235
- remove(path, type) {
236
-
237
- const assetDescription = new AssetDescription(path, type);
238
-
239
- return this.assets.delete(assetDescription);
240
- }
241
-
242
- /**
243
- * Clear out all loaded assets
244
- */
245
- clear() {
246
- this.assets.clear();
247
- }
248
-
249
- dumpLoadedAssetList() {
250
- return JSON.stringify(extractAssetListFromManager(this), 3, 3);
251
- }
252
-
253
- /**
254
- * @param {String} path
255
- * @param {String} type
256
- * @param {AssetRequestScope} [scope]
257
- * @param {boolean} [skip_queue] if true will skip the queue and dispatch request immediately
258
- * @returns {Promise<Asset>}
259
- */
260
- promise(path, type, { scope, skip_queue = false } = {}) {
261
- return new Promise((resolve, reject) => {
262
- this.get({
263
- path,
264
- type,
265
- callback: resolve,
266
- failure: reject,
267
- scope
268
- });
269
- });
270
- }
271
-
272
- /**
273
- * @template T
274
- * @param {String} path
275
- * @param {String} type
276
- * @param {function(asset:Asset<T>)} [callback] success callback
277
- * @param {function(reason:*)} [failure]
278
- * @param {function(loaded:number, total:number)} [progress]
279
- * @param {boolean} [skip_queue]
280
- * @param {AssetRequestScope} [scope]
281
- */
282
- get({
283
- path,
284
- type,
285
- callback = noop,
286
- failure = console.error,
287
- progress = noop,
288
- skip_queue = false,
289
- scope = null
290
- }) {
291
-
292
- if (typeof path !== "string") {
293
- throw new TypeError(`Path must be string. instead was '${typeof path}'`);
294
- }
295
-
296
- if (typeof type !== "string") {
297
- throw new TypeError(`type must be a string, instead was '${typeof type}'`);
298
- }
299
-
300
- assert.isFunction(callback, 'success');
301
- assert.isFunction(failure, 'failure');
302
- assert.isFunction(progress, 'progress');
303
-
304
- const assetDescription = new AssetDescription(path, type);
305
-
306
- const asset = this.assets.get(assetDescription);
307
-
308
- if (asset !== undefined) {
309
-
310
- // already exists, dispatch callback immediately
311
- callback(asset);
312
-
313
- } else {
314
-
315
- //create request object
316
- const assetRequest = new AssetRequest(callback, failure, progress);
317
-
318
- assetRequest.scope = scope;
319
- assetRequest.writeFlag(AssetRequestFlags.SkipQueue, skip_queue);
320
-
321
- //submit request
322
- this.submitRequest(assetDescription, assetRequest);
323
-
324
- }
325
- }
326
-
327
- /**
328
- * Checks if an asset is currently being loaded.
329
- * Useful for avoiding redundant requests.
330
- *
331
- * @param {string} path
332
- * @param {string} type
333
- * @return {boolean}
334
- */
335
- isPending(path, type) {
336
- const assetDescription = new AssetDescription(path, type);
337
- return this.request_map.has(assetDescription);
338
- }
339
-
340
-
341
- /**
342
- *
343
- * @param {string} path
344
- * @param {string} type
345
- * @returns {boolean}
346
- * @see isPending
347
- */
348
- isFailed(path, type) {
349
- const ad = new AssetDescription(path, type);
350
-
351
- return this.#failures.has(ad);
352
- }
353
-
354
- /**
355
- * Checks if an asset is loaded.
356
- * If the asset is loaded, calls to {@link tryGet} are guaranteed to succeed.
357
- *
358
- * @param {string} path
359
- * @param {string} type
360
- * @return {boolean}
361
- */
362
- isLoaded(path, type) {
363
- const ad = new AssetDescription(path, type);
364
-
365
- return this.assets.has(ad);
366
- }
367
-
368
- /**
369
- * Same as {@link insert}, but will register the asset as pending until loader function resolves.
370
- *
371
- * NOTE: {@link AssetTransformer}s are not applied to the asset
372
- *
373
- * NOTE: any subsequent normal requests such as {@link get} will be routed to the same loader
374
- *
375
- * @template T
376
- * @param {string} path
377
- * @param {string} type
378
- * @param {function(progress?:function(current:number, total:number)):Promise<Asset<T>>} loader
379
- * @returns {Promise<Asset<T>>} loaded asset
380
- * @see insert
381
- * @example
382
- * manager.insertAsync('path/to/asset', 'my-type', async (progress) => {
383
- * const asset = await loadAssetFromNetwork('path/to/asset', 'type', progress);
384
- * return asset;
385
- * });
386
- *
387
- */
388
- insertAsync(path, type, loader) {
389
-
390
- const asset_descriptor = new AssetDescription(path, type);
391
-
392
- if (this.request_map.get(asset_descriptor)) {
393
- throw new Error(`Asset with path '${path}' and type '${type}' is already pending`);
394
- }
395
-
396
- const pending = new PendingAsset(asset_descriptor);
397
-
398
- this.request_map.set(asset_descriptor, pending);
399
-
400
- /**
401
- *
402
- * @param {number} current
403
- * @param {number} total
404
- */
405
- const progress = (current, total) => {
406
- pending.progress.setValue(current);
407
- pending.progress.setUpperLimit(total);
408
- };
409
-
410
- const asset_promise = loader(progress);
411
-
412
- const cleanup = () => {
413
- const existing = this.request_map.get(asset_descriptor);
414
-
415
- if (existing !== pending) {
416
- // looks like another resolution is pending, this completely invalidates current insersion request
417
- // Likely reason is that something else was inserted later on
418
- return false;
419
- }
420
-
421
- this.request_map.delete(asset_descriptor);
422
- return true;
423
- }
424
-
425
- return asset_promise.then(asset => {
426
- const existing = this.request_map.get(asset_descriptor);
427
-
428
- if (existing !== pending) {
429
- // looks like another resolution is pending, this completely invalidates current insersion request
430
- // Likely reason is that something else was inserted later on
431
- throw new Error(`Race condition. Asset with path '${path}' and type '${type}' was already resolved somewhere else.`);
432
- }
433
-
434
- this.insert(path, type, asset);
435
-
436
- return asset;
437
- }, error => {
438
- cleanup();
439
-
440
- //rethrow
441
- throw error;
442
- });
443
- }
444
-
445
- /**
446
- * Manually add a fully resolved resource
447
- * NOTE: {@link AssetTransformer}s are not applied to the asset
448
- *
449
- * @template T
450
- * @param {string} path
451
- * @param {string} type
452
- * @param {Asset<T>} asset
453
- */
454
- insert(path, type, asset) {
455
- assert.isString(path, 'path');
456
- assert.isString(type, 'type');
457
- assert.isObject(asset, 'asset');
458
-
459
- const asset_descritptor = new AssetDescription(path, type);
460
-
461
- const existing_resource = this.assets.get(asset_descritptor);
462
-
463
- if (existing_resource !== undefined && existing_resource !== asset) {
464
- console.warn(`Another asset under ${asset_descritptor} already exists and will be replaced`);
465
- }
466
-
467
- // clear failures
468
- this.#failures.delete(asset_descritptor);
469
-
470
- // check for assets in-flight
471
- const pending = this.request_map.get(asset_descritptor);
472
- if (pending !== undefined) {
473
- // TODO check 'active' flight sets as well
474
- // console.warn(`Asset with path '${path}' and type '${type}' is already pending, this operation will squash the asset in-flight`);
475
-
476
- this.request_map.delete(asset_descritptor);
477
-
478
- const requests = pending.requests;
479
- const request_count = requests.length;
480
-
481
- for (let i = 0; i < request_count; i++) {
482
- const request = requests[i];
483
- this.#schedule_response(asset, request);
484
- }
485
- }
486
-
487
- this.assets.set(asset_descritptor, asset);
488
- }
489
-
490
- /**
491
- *
492
- * @param {Response} response
493
- * @private
494
- */
495
- #process_response(response) {
496
-
497
- try {
498
- response.request.successCallback(response.asset);
499
- } catch (e) {
500
- console.error("Failed to execute asset success callback", e);
501
- }
502
- }
503
-
504
- /**
505
- *
506
- * @param {Asset} asset
507
- * @param {AssetRequest} request
508
- * @private
509
- */
510
- #schedule_response(asset, request) {
511
- // technically you can schedule responses just fine, but commonly the user forgets to call 'startup' and so nothing happens which is perceived as a bug.
512
- assert.equal(this.#is_running, true, 'AssetManager must be running to schedule responses');
513
-
514
- this.#response_queue.add(new Response(asset, request));
515
- }
516
-
517
- /**
518
- *
519
- * @param {PendingAsset} asset
520
- * @private
521
- */
522
- #schedule_load(asset) {
523
- if (this.#pending_asset_active_load_set.size < this.load_concurrency) {
524
- this.#dispatch_pending_asset(asset);
525
- } else {
526
- this.#pending_asset_wait_queue.push(asset);
527
- }
528
- }
529
-
530
- /**
531
- * Force load of the asset
532
- * @param {PendingAsset} asset
533
- * @private
534
- */
535
- #force_load(asset) {
536
- // check if the asset is already being loaded
537
- if (this.#pending_asset_active_load_set.has(asset)) {
538
- return;
539
- }
540
-
541
- // remove from queue
542
- this.#pending_asset_wait_queue.delete(asset);
543
-
544
- // dispatch
545
- this.#dispatch_pending_asset(asset);
546
-
547
- }
548
-
549
- /**
550
- * Asset has been loaded successfully, failed, or aborted
551
- * @param {PendingAsset} pending_asset
552
- * @private
553
- */
554
- #handle_asset_resolved(pending_asset) {
555
- // console.log(`Asset resolved ${pending_asset.description}`); // DEBUG
556
-
557
- const active_set = this.#pending_asset_active_load_set;
558
-
559
- this.request_map.delete(pending_asset.description);
560
- active_set.delete(pending_asset);
561
-
562
- const queue = this.#pending_asset_wait_queue;
563
-
564
- // schedule more if possible
565
- while (!queue.isEmpty() && active_set.size < this.load_concurrency) {
566
- const load = queue.pop();
567
-
568
- this.#dispatch_pending_asset(load);
569
- }
570
- }
571
-
572
- /**
573
- * Dispatch load request to relevant loader
574
- * @param {PendingAsset} pendingAsset
575
- * @private
576
- */
577
- #dispatch_pending_asset(pendingAsset) {
578
- // console.log(`Asset load dispatched ${pendingAsset.description}`); // DEBUG
579
-
580
- const requests = pendingAsset.requests;
581
- const assetDescription = pendingAsset.description;
582
- const type = assetDescription.type;
583
- const path = assetDescription.path;
584
-
585
- const loader = this.#loaders[type];
586
-
587
- if (loader === undefined) {
588
- let reported_error = false;
589
- // no loader
590
- for (let i = 0; i < requests.length; i++) {
591
- const assetRequest = requests[i];
592
-
593
- if (typeof assetRequest.failureCallback === "function") {
594
- assetRequest.failureCallback(`no loader exists for asset type '${type}', valid types are: ${Object.keys(this.#loaders).join(', ')}`);
595
- } else {
596
- //uncaught
597
- if (!reported_error) {
598
- console.error("Uncaught asset load failure: No loader for asset type", type);
599
- reported_error = true;
600
- }
601
- }
602
- }
603
-
604
- this.#handle_asset_resolved(pendingAsset);
605
-
606
- return;
607
- }
608
-
609
- // mark as being loaded
610
- this.#pending_asset_active_load_set.add(pendingAsset);
611
-
612
- const assets = this.assets;
613
- const failures = this.#failures;
614
-
615
-
616
- /**
617
- *
618
- * @param {Asset} loaded_asset
619
- */
620
- const success = async (loaded_asset) => {
621
- if (pendingAsset.state === AssetLoadState.Succeeded) {
622
- // incorrect state
623
- console.warn(`Asset already resolved, duplicate success invocation. Ignored. AD:${assetDescription}`);
624
- return;
625
- }
626
-
627
- if (pendingAsset.state === AssetLoadState.Failed) {
628
- // incorrect state
629
- console.error(`Asset already failed. Unexpected resolution signal. AD:${assetDescription}`);
630
- }
631
-
632
- pendingAsset.state = AssetLoadState.Succeeded;
633
-
634
- let asset = loaded_asset;
635
-
636
- // apply the transform chain
637
- const transformers = this.#transformers[type];
638
- if (transformers !== undefined) {
639
- const transformer_count = transformers.length;
640
- for (let i = 0; i < transformer_count; i++) {
641
- const transformer = transformers[i];
642
-
643
- const transformed_asset = await transformer.transform(asset, assetDescription);
644
-
645
- if (typeof transformed_asset !== "object") {
646
- console.error('Transformer produced invalid result. Ignoring result.', transformer, assetDescription);
647
- } else {
648
- asset = transformed_asset;
649
- }
650
- }
651
- }
652
-
653
- // link asset description
654
- asset.description = assetDescription;
655
-
656
- // clear possible failure
657
- this.#failures.delete(assetDescription);
658
-
659
- // register asset
660
- assets.set(assetDescription, asset);
661
-
662
- // clear callbacks etc.
663
- this.#handle_asset_resolved(pendingAsset);
664
-
665
-
666
- // process callbacks
667
- for (let i = 0; i < requests.length; i++) {
668
- const request = requests[i];
669
- this.#schedule_response(asset, request);
670
- }
671
-
672
- }
673
-
674
- const failure = (error) => {
675
- if (pendingAsset.state === AssetLoadState.Failed) {
676
- console.warn(`Asset already failed, this is a redundant invocation. AD: ${assetDescription}`);
677
- return;
678
- }
679
-
680
- if (pendingAsset.state === AssetLoadState.Succeeded) {
681
- // incorrect state
682
- console.error(`Asset already resolved. Unexpected failure signal. AD:${assetDescription}`);
683
- }
684
-
685
- pendingAsset.state = AssetLoadState.Failed;
686
-
687
- for (let i = 0; i < requests.length; i++) {
688
- const request = requests[i];
689
- try {
690
- request.failureCallback(error);
691
- } catch (e) {
692
- console.error("Failed to execute asset failure callback", e);
693
- }
694
- }
695
-
696
- //clear callbacks etc.
697
- this.#handle_asset_resolved(pendingAsset);
698
-
699
- // record failure
700
- failures.add(assetDescription);
701
- }
702
-
703
- function progress(current, total) {
704
- requests.forEach(function (request) {
705
- if (typeof request.pogressCallback !== "function") {
706
- //progress callback is not a function, ignore
707
- return;
708
- }
709
-
710
- try {
711
- request.pogressCallback(current, total);
712
- } catch (e) {
713
- console.error("Failed to execute asset progress callback", e);
714
- }
715
- });
716
-
717
- pendingAsset.progress.setValue(current);
718
- pendingAsset.progress.setUpperLimit(total);
719
- }
720
-
721
- // collect scopes
722
- const scopes = [];
723
-
724
- for (let i = 0; i < requests.length; i++) {
725
- const request = requests[i];
726
- const request_scope = request.scope;
727
-
728
- if (request_scope !== null) {
729
- array_push_if_unique(scopes, request_scope)
730
- }
731
- }
732
-
733
- let scope;
734
- if (scopes.length > 0) {
735
- scope = AssetRequestScope.from(scopes);
736
- } else {
737
- scope = AssetRequestScope.GLOBAL;
738
- }
739
-
740
-
741
- const full_path = this.rootPath + path;
742
-
743
- // console.log(`Request type: ${type}, path: ${path}, scope: ${scope}`);
744
-
745
- try {
746
-
747
-
748
- const result = loader.load(scope, full_path, success, failure, progress);
749
-
750
- if (result instanceof Promise) {
751
- // allow promise responses
752
- result.catch(failure);
753
- }
754
-
755
- } catch (e) {
756
- console.error(`Loader failed on invocation. path=${path}, type=${type}`, 'Loader exception: ', e);
757
- failure(e);
758
- }
759
- }
760
-
761
- /**
762
- *
763
- * @param {AssetDescription} assetDescription
764
- * @param {AssetRequest} request
765
- * @private
766
- */
767
- submitRequest(assetDescription, request) {
768
- const requestMap = this.request_map;
769
-
770
- let shouldSchedule = false;
771
- let pendingAsset = requestMap.get(assetDescription);
772
-
773
- if (pendingAsset === undefined) {
774
- pendingAsset = new PendingAsset(assetDescription);
775
- requestMap.set(assetDescription, pendingAsset);
776
-
777
- shouldSchedule = true;
778
- }
779
-
780
- pendingAsset.requests.push(request);
781
-
782
- if (shouldSchedule) {
783
- // not loading yet, lets create a load container and schedule it
784
- this.#schedule_load(pendingAsset);
785
- } else {
786
- // update priority queue if necessary
787
- this.#pending_asset_wait_queue.updateElementScore(pendingAsset);
788
- }
789
-
790
-
791
- if (request.getFlag(AssetRequestFlags.SkipQueue)) {
792
- this.#force_load(pendingAsset);
793
- }
794
- }
795
-
796
-
797
- /**
798
- *
799
- * @param {string} type
800
- * @return {boolean}
801
- */
802
- hasLoaderForType(type) {
803
- return this.getLoaderByType(type) !== undefined;
804
- }
805
-
806
- /**
807
- *
808
- * @param {string} type
809
- * @returns {AssetLoader|undefined}
810
- */
811
- getLoaderByType(type) {
812
- assert.isString(type, 'type');
813
-
814
- return this.#loaders[type];
815
- }
816
-
817
- /**
818
- *
819
- * @param {string} type
820
- * @return {AssetDescription[]}
821
- * @private
822
- */
823
- #getLoadedAssetDescriptorsByType(type) {
824
- const loaded_assets = Array.from(this.assets.keys());
825
- return loaded_assets.filter(t => t.type === type);
826
- }
827
-
828
- /**
829
- * Transformer will be applied to all assets of the given type in order of registration.
830
- *
831
- * Does not apply retroactively, assets that were already loaded will not be transformed.
832
- *
833
- * @template T
834
- * @param {string} type
835
- * @param {AssetTransformer<T>} transformer
836
- * @returns {void}
837
- * @see removeTransformer
838
- */
839
- registerTransformer(type, transformer) {
840
- let transformers = this.#transformers[type];
841
-
842
- if (transformers === undefined) {
843
- transformers = [];
844
-
845
- this.#transformers[type] = transformers;
846
- }
847
-
848
- transformers.push(transformer);
849
-
850
- // check for loaded assets
851
- const matching_assets = this.#getLoadedAssetDescriptorsByType(type);
852
-
853
- if (matching_assets.length > 0) {
854
- console.warn(`Following assets of matching type '${type}' are already loaded and transform is not applied to them:\n\t${matching_assets.join('\n\t')}`);
855
- }
856
-
857
- }
858
-
859
- /**
860
- * @template T
861
- * @param {string} type
862
- * @param {AssetTransformer<T>} transformer
863
- * @returns {boolean} true if removed, false if not found
864
- * @see registerTransformer
865
- */
866
- unregisterTransformer(type, transformer) {
867
-
868
- const transformers = this.#transformers[type];
869
-
870
- if (transformers === undefined) {
871
- // not found
872
- return false;
873
- }
874
-
875
- if (!array_remove_first(transformers, transformer)) {
876
- // not found
877
- return false;
878
- }
879
-
880
- // check for loaded assets
881
- const matching_assets = this.#getLoadedAssetDescriptorsByType(type);
882
-
883
- if (matching_assets.length > 0) {
884
- console.warn(`Following assets of matching type '${type}' are already loaded and transform was probably already applied to them:\n\t${matching_assets.join('\n\t')}`);
885
- }
886
-
887
- return true;
888
- }
889
-
890
- /**
891
- * Will register loader only if none exists for this type
892
- * @template T
893
- * @param {string} type
894
- * @param {AssetLoader<T>} loader
895
- * @returns {Promise<boolean>} true if registered, false otherwise
896
- */
897
- async tryRegisterLoader(type, loader) {
898
- if (this.hasLoaderForType(type)) {
899
- return false;
900
- }
901
-
902
- await this.registerLoader(type, loader);
903
-
904
- return true;
905
- }
906
-
907
- /**
908
- * @template T
909
- * @param {string} type
910
- * @param {AssetLoader<T>} loader
911
- * @throws {Error} if a loader is already registered for the given type
912
- */
913
- async registerLoader(type, loader) {
914
- assert.isString(type, 'type');
915
-
916
- const existing_loader = this.getLoaderByType(type);
917
-
918
- if (existing_loader !== undefined) {
919
- if (existing_loader === loader) {
920
- // all is well, already registered
921
- return existing_loader;
922
- } else if (Object.getPrototypeOf(existing_loader) === Object.getPrototypeOf(loader)) {
923
- console.warn(`Another instance of this loader is already registered for type '${type}'. Ignoring.`);
924
- return existing_loader;
925
- } else {
926
- throw new Error(`Loader for type '${type}' is already registered`);
927
- }
928
- }
929
-
930
-
931
- let _loader = loader;
932
-
933
- if (typeof _loader === "function") {
934
-
935
- _loader = new AssetLoader();
936
- _loader.load = loader;
937
-
938
- console.warn(`function-based loaders are deprecated (${type})`);
939
-
940
- } else {
941
-
942
- await _loader.link(this, this.#context);
943
-
944
- }
945
-
946
- this.#loaders[type] = _loader;
947
-
948
- return _loader;
949
- }
950
-
951
- /**
952
- *
953
- * @param {string} type
954
- */
955
- async unregisterLoader(type) {
956
- const loader = this.getLoaderByType(type);
957
-
958
- if (loader === undefined) {
959
- // asset loader is not registered, nothing to do
960
- return;
961
-
962
- }
963
-
964
- // first remove the loader from registry so no further asset requests can be made
965
- delete this.#loaders[type];
966
-
967
- // TODO address all pending requests, possibly waiting for all of them to finalize
968
-
969
- // finally unlink the loader
970
- await loader.unlink();
971
- }
972
-
973
- /**
974
- * Retrieve an asset if it is loaded, returns null if the asset is not loaded.
975
- * Does not trigger loading if the asset is not loaded.
976
- * @template T
977
- * @param {String} path
978
- * @param {String} type
979
- * @returns {Asset<T>|null}
980
- */
981
- tryGet(path, type) {
982
- const assetDescription = new AssetDescription(path, type);
983
-
984
- const asset = this.assets.get(assetDescription);
985
-
986
- if (asset !== undefined) {
987
- return asset;
988
- } else {
989
- return null;
990
- }
991
- }
992
-
993
- /**
994
- * @template T
995
- * @param {string} alias
996
- * @return {Promise<Asset<T>>}
997
- */
998
- promiseByAlias(alias) {
999
- assert.isString(alias, 'alias');
1000
-
1001
- // resolve alias
1002
- const assetDescription = this.#aliases.get(alias);
1003
-
1004
- if (assetDescription === undefined) {
1005
- return new Promise.reject(`Alias '${alias}' not found`);
1006
- }
1007
-
1008
- return this.promise(assetDescription.path, assetDescription.path);
1009
- }
1010
-
1011
- /**
1012
- *
1013
- * @param {string} alias
1014
- * @return {AssetDescription|undefined}
1015
- */
1016
- resolveAlias(alias) {
1017
-
1018
- // todo consider cloning result to protect against mutation
1019
-
1020
- return this.#aliases.get(alias);
1021
-
1022
- }
1023
-
1024
- /**
1025
- *
1026
- * @param {string} alias
1027
- * @param {string} path
1028
- * @param {string} type
1029
- */
1030
- assignAlias(alias, path, type) {
1031
- assert.isString(alias, 'alias');
1032
- assert.isString(path, 'path');
1033
- assert.isString(type, 'type');
1034
-
1035
- const assetDescription = new AssetDescription(path, type);
1036
-
1037
- this.#aliases.set(alias, assetDescription);
1038
- }
1039
- }
1040
-
1041
- /**
1042
- * @readonly
1043
- * @type {boolean}
1044
- */
1045
- AssetManager.prototype.isAssetManager = true;
1
+ import { assert } from "../../core/assert.js";
2
+ import { array_push_if_unique } from "../../core/collection/array/array_push_if_unique.js";
3
+ import { array_remove_first } from "../../core/collection/array/array_remove_first.js";
4
+ import BinaryHeap from "../../core/collection/heap/BinaryHeap.js";
5
+ import { HashMap } from "../../core/collection/map/HashMap.js";
6
+ import { ObservedMap } from "../../core/collection/map/ObservedMap.js";
7
+ import { Deque } from "../../core/collection/queue/Deque.js";
8
+ import { HashSet } from "../../core/collection/set/HashSet.js";
9
+ import { noop } from "../../core/function/noop.js";
10
+ import ConcurrentExecutor from "../../core/process/executor/ConcurrentExecutor.js";
11
+ import Task from "../../core/process/task/Task.js";
12
+ import { TaskSignal } from "../../core/process/task/TaskSignal.js";
13
+ import { AssetDescription } from "./AssetDescription.js";
14
+ import { AssetLoadState } from "./AssetLoadState.js";
15
+ import { AssetRequest, AssetRequestFlags } from "./AssetRequest.js";
16
+ import { AssetRequestScope } from "./AssetRequestScope.js";
17
+ import { CrossOriginConfig } from "./CORS/CrossOriginConfig.js";
18
+ import { AssetLoader } from "./loaders/AssetLoader.js";
19
+ import { PendingAsset } from "./PendingAsset.js";
20
+ import { extractAssetListFromManager } from "./preloader/extractAssetListFromManager.js";
21
+
22
+
23
+ class Response {
24
+ /**
25
+ *
26
+ * @param {AssetRequest} request
27
+ * @param {Asset|*} value loaded asset when success is true, error otherwise
28
+ * @param {boolean} success
29
+ * @param {AssetDescription} description
30
+ */
31
+ constructor(request, value, success, description) {
32
+ this.request = request;
33
+ this.value = value;
34
+ this.success = success;
35
+ this.description = description;
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Used by the priority queue, so the priority is inverted as the BinaryHeap returns elements in ascending score order (from lowest)
41
+ * @param {PendingAsset} pending_asset
42
+ * @returns {number}
43
+ */
44
+ function get_pending_asset_priority_score(pending_asset) {
45
+ return -pending_asset.priority;
46
+ }
47
+
48
+
49
+ // TODO handle 429 HTTP error gracefully
50
+
51
+ /**
52
+ * Handles loading/generating assets
53
+ * @template CTX
54
+ * @class
55
+ */
56
+ export class AssetManager {
57
+ /**
58
+ *
59
+ * @type {HashMap<AssetDescription, Asset>}
60
+ * @private
61
+ */
62
+ assets = new HashMap({
63
+ capacity: 1024
64
+ });
65
+
66
+ /**
67
+ *
68
+ * @type {ObservedMap<AssetDescription, PendingAsset>}
69
+ */
70
+ request_map = new ObservedMap(new HashMap());
71
+
72
+ /**
73
+ * Waiting queue for assets that haven't yet been scheduled (passed to relevant loader)
74
+ * @type {BinaryHeap<PendingAsset>}
75
+ * @private
76
+ */
77
+ #pending_asset_wait_queue = new BinaryHeap(get_pending_asset_priority_score);
78
+ /**
79
+ * Assets currently being processed by #loaders
80
+ * @type {Set<PendingAsset>}
81
+ * @private
82
+ */
83
+ #pending_asset_active_load_set = new Set();
84
+
85
+ /**
86
+ * Dispatch scopes of loads that are currently in flight. A request whose scope chain reaches
87
+ * one of these was made by a loader as part of that load (a nested request).
88
+ * @type {Map<AssetRequestScope, PendingAsset>}
89
+ * @private
90
+ */
91
+ #active_load_scopes = new Map();
92
+
93
+ /**
94
+ * Maximum number of top-level requests that can be handled at the same time.
95
+ * Since most of the requests are handled over the network, this can help you control network concurrency,
96
+ * this can be useful to keep some network slots available for high-priority requests such as UI related ones.
97
+ * Nested requests (made by a loader while servicing another load) are dispatched immediately and never wait
98
+ * on this limit: their parent occupies a slot until they resolve, so queueing them would deadlock.
99
+ * @type {number}
100
+ */
101
+ load_concurrency = Infinity;
102
+
103
+ /**
104
+ * Registered asset loaders
105
+ * @private
106
+ * @type {Object<AssetLoader>}
107
+ */
108
+ #loaders = {};
109
+
110
+ /**
111
+ * After an asset is loaded, a chain of transforms can be applied to it, these are registered here
112
+ * Transformers are executed in the order in which they are added
113
+ * Identified by asset "type" string
114
+ * @type {Object<AssetTransformer[]>}
115
+ * @private
116
+ */
117
+ #transformers = {};
118
+
119
+ /**
120
+ * Named links to specific assets. Useful to later re-mapping assets and having meaningful names for them
121
+ * @type {Map<string, AssetDescription>}
122
+ * @private
123
+ * @see resolveAlias
124
+ * @see assignAlias
125
+ * @see promiseByAlias
126
+ */
127
+ #aliases = new Map();
128
+
129
+ /**
130
+ * This will be added to asset path for actual network resolution.
131
+ * Paths exchanged with the manager ({@link get}, {@link promise}, cache keys) are never prefixed;
132
+ * loaders apply the prefix at the fetch boundary via {@link resolveNetworkPath}.
133
+ * @type {string}
134
+ * @private
135
+ */
136
+ rootPath = '';
137
+
138
+ /**
139
+ *
140
+ * @type {CrossOriginConfig}
141
+ */
142
+ crossOriginConfig = new CrossOriginConfig();
143
+
144
+ /**
145
+ * Descriptions of assets whose most recent load attempt failed.
146
+ * Purely advisory (see {@link isFailed}); a new {@link get} for a failed asset will retry the load.
147
+ * @type {HashSet<AssetDescription>}
148
+ * @private
149
+ */
150
+ #failures = new HashSet();
151
+
152
+ /**
153
+ * Queue of responses that are waiting to be dispatched
154
+ * @type {Deque<Response>}
155
+ * @private
156
+ */
157
+ #response_queue = new Deque();
158
+
159
+ /**
160
+ * Resolvers of {@link shutdown} calls that are waiting for outstanding work to finish
161
+ * @type {function[]}
162
+ * @private
163
+ */
164
+ #drain_waiters = [];
165
+
166
+ /**
167
+ * Delivers queued responses. Ends as soon as the queue is drained and is re-scheduled by
168
+ * {@link #wake_response_processor} when a new response is enqueued, so an idle manager keeps
169
+ * no task on the executor and the executor itself can go fully idle.
170
+ * @type {Task}
171
+ * @private
172
+ */
173
+ #response_processor = new Task({
174
+ name: "Asset Manager Response processor",
175
+ cycleFunction: () => {
176
+ if (this.#response_queue.isEmpty()) {
177
+ this.#flush_drain_waiters();
178
+
179
+ return TaskSignal.EndSuccess;
180
+ }
181
+
182
+ const response = this.#response_queue.removeFirst();
183
+
184
+ this.#process_response(response);
185
+
186
+ return TaskSignal.Continue;
187
+ }
188
+ });
189
+
190
+ /**
191
+ * True when a wake of {@link #response_processor} is already sitting on the microtask queue
192
+ * @type {boolean}
193
+ * @private
194
+ */
195
+ #wake_queued = false;
196
+
197
+ /**
198
+ * Deferred half of {@link #wake_response_processor}. By the time the microtask fires the world
199
+ * may have changed (manager shut down, queue already drained, processor already scheduled), so
200
+ * every condition is re-checked here.
201
+ */
202
+ #wake = () => {
203
+ this.#wake_queued = false;
204
+
205
+ if (!this.#is_running) {
206
+ // shut down before the wake fired; #abort_outstanding has already delivered the queue
207
+ return;
208
+ }
209
+
210
+ if (this.#response_queue.isEmpty()) {
211
+ // queue was drained before the wake fired
212
+ return;
213
+ }
214
+
215
+ if (this.#executor.contains(this.#response_processor)) {
216
+ // processor is already scheduled and will drain the queue
217
+ return;
218
+ }
219
+
220
+ this.#executor.run(this.#response_processor);
221
+ };
222
+
223
+ /**
224
+ * Schedules {@link #response_processor} to run. Deferred via the microtask queue: responses are
225
+ * enqueued from inside {@link #settle} (e.g. by {@link insert} or a loader callback), and
226
+ * {@link ConcurrentExecutor#run} executes a time slice synchronously — waking the processor
227
+ * directly would deliver requester callbacks synchronously to whoever caused the settle.
228
+ * @private
229
+ */
230
+ #wake_response_processor() {
231
+ if (this.#wake_queued) {
232
+ return;
233
+ }
234
+
235
+ this.#wake_queued = true;
236
+
237
+ queueMicrotask(this.#wake);
238
+ }
239
+
240
+ /**
241
+ *
242
+ * @type {boolean}
243
+ * @private
244
+ */
245
+ #is_running = false;
246
+
247
+ /**
248
+ *
249
+ * @type {CTX|null}
250
+ * @private
251
+ */
252
+ #context = null;
253
+
254
+ /**
255
+ *
256
+ * @type {ConcurrentExecutor|null}
257
+ */
258
+ #executor = null;
259
+
260
+ /**
261
+ *
262
+ * @param {CTX} context
263
+ * @param {ConcurrentExecutor} executor
264
+ * @constructor
265
+ */
266
+ constructor({
267
+ context,
268
+ executor = new ConcurrentExecutor()
269
+ } = {}) {
270
+
271
+ this.#context = context;
272
+ this.#executor = executor;
273
+
274
+ }
275
+
276
+ startup() {
277
+ if (this.#is_running) {
278
+ return;
279
+ }
280
+
281
+ this.#is_running = true;
282
+
283
+ // deliver anything that was enqueued before startup
284
+ if (!this.#response_queue.isEmpty()) {
285
+ this.#wake_response_processor();
286
+ }
287
+ }
288
+
289
+ /**
290
+ *
291
+ * @param {boolean} [immediate] should we let pending work finish, or shut down immediately?
292
+ * Defaults to false (wait until all in-flight requests are resolved and all responses are delivered).
293
+ * When true, outstanding requests are failed and all responses are delivered before the method returns.
294
+ * @return {Promise<void>}
295
+ */
296
+ async shutdown(immediate = false) {
297
+ if (!this.#is_running) {
298
+ return;
299
+ }
300
+
301
+ if (!immediate) {
302
+ await this.#drain();
303
+ } else {
304
+ this.#abort_outstanding();
305
+ }
306
+
307
+ this.#executor.removeTask(this.#response_processor);
308
+
309
+ this.#is_running = false;
310
+ }
311
+
312
+ /**
313
+ * Fail every outstanding request and deliver all queued responses synchronously.
314
+ * In-flight loaders keep running, but their late resolutions will be dropped by the claim guard.
315
+ * @private
316
+ */
317
+ #abort_outstanding() {
318
+ // empty the wait queue first, otherwise settling an active load would pop and dispatch queued ones
319
+ const queue = this.#pending_asset_wait_queue;
320
+
321
+ while (!queue.isEmpty()) {
322
+ queue.pop();
323
+ }
324
+
325
+ /**
326
+ * @type {PendingAsset[]}
327
+ */
328
+ const outstanding = [];
329
+
330
+ this.request_map.forEach(pending => outstanding.push(pending));
331
+
332
+ if (outstanding.length > 0) {
333
+ const error = new Error('AssetManager was shut down before the asset resolved');
334
+
335
+ for (let i = 0; i < outstanding.length; i++) {
336
+ const pending = outstanding[i];
337
+
338
+ pending.resolution_claimed = true;
339
+ this.#settle(pending, AssetLoadState.Failed, error);
340
+ }
341
+ }
342
+
343
+ // the response processor is about to be removed, deliver everything now
344
+ while (!this.#response_queue.isEmpty()) {
345
+ this.#process_response(this.#response_queue.removeFirst());
346
+ }
347
+
348
+ // a graceful shutdown() may still be waiting on the drain
349
+ this.#flush_drain_waiters();
350
+ }
351
+
352
+ /**
353
+ * Resolves once there are no in-flight requests and no undelivered responses.
354
+ * @returns {Promise<void>}
355
+ * @private
356
+ */
357
+ #drain() {
358
+ if (this.#response_queue.isEmpty() && this.request_map.size === 0) {
359
+ return Promise.resolve();
360
+ }
361
+
362
+ return new Promise(resolve => this.#drain_waiters.push(resolve));
363
+ }
364
+
365
+ /**
366
+ * @private
367
+ */
368
+ #flush_drain_waiters() {
369
+ if (this.#drain_waiters.length === 0) {
370
+ return;
371
+ }
372
+
373
+ if (!this.#response_queue.isEmpty() || this.request_map.size > 0) {
374
+ // still busy
375
+ return;
376
+ }
377
+
378
+ const waiters = this.#drain_waiters;
379
+ this.#drain_waiters = [];
380
+
381
+ for (let i = 0; i < waiters.length; i++) {
382
+ waiters[i]();
383
+ }
384
+ }
385
+
386
+ /**
387
+ * Resolves a caller-facing asset path to the path used for actual network retrieval.
388
+ * Loaders that fetch over the network should apply this at the fetch boundary; paths passed to
389
+ * {@link get}/{@link promise} (including nested requests made by loaders) always stay un-prefixed,
390
+ * so they are keyed consistently in the cache.
391
+ * @param {string} path
392
+ * @returns {string}
393
+ */
394
+ resolveNetworkPath(path) {
395
+ return this.rootPath + path;
396
+ }
397
+
398
+ /**
399
+ * Remove asset if it is loaded, does nothing otherwise
400
+ * @param {String} path
401
+ * @param {String} type
402
+ * @returns {boolean} true if asset was removed, else otherwise
403
+ */
404
+ remove(path, type) {
405
+
406
+ const assetDescription = new AssetDescription(path, type);
407
+
408
+ return this.assets.delete(assetDescription);
409
+ }
410
+
411
+ /**
412
+ * Clear out all loaded assets
413
+ */
414
+ clear() {
415
+ this.assets.clear();
416
+ }
417
+
418
+ dumpLoadedAssetList() {
419
+ return JSON.stringify(extractAssetListFromManager(this), null, 3);
420
+ }
421
+
422
+ /**
423
+ * @param {String} path
424
+ * @param {String} type
425
+ * @param {AssetRequestScope} [scope]
426
+ * @param {boolean} [skip_queue] if true will skip the queue and dispatch request immediately
427
+ * @param {function(loaded:number, total:number)} [progress]
428
+ * @returns {Promise<Asset>}
429
+ */
430
+ promise(path, type, { scope, skip_queue = false, progress } = {}) {
431
+ return new Promise((resolve, reject) => {
432
+ this.get({
433
+ path,
434
+ type,
435
+ callback: resolve,
436
+ failure: reject,
437
+ progress,
438
+ skip_queue,
439
+ scope
440
+ });
441
+ });
442
+ }
443
+
444
+ /**
445
+ * @template T
446
+ * @param {String} path
447
+ * @param {String} type
448
+ * @param {function(asset:Asset<T>)} [callback] success callback
449
+ * @param {function(reason:*)} [failure]
450
+ * @param {function(loaded:number, total:number)} [progress]
451
+ * @param {boolean} [skip_queue]
452
+ * @param {AssetRequestScope} [scope]
453
+ */
454
+ get({
455
+ path,
456
+ type,
457
+ callback = noop,
458
+ failure = console.error,
459
+ progress = noop,
460
+ skip_queue = false,
461
+ scope = null
462
+ }) {
463
+
464
+ if (typeof path !== "string") {
465
+ throw new TypeError(`Path must be string. instead was '${typeof path}'`);
466
+ }
467
+
468
+ if (typeof type !== "string") {
469
+ throw new TypeError(`type must be a string, instead was '${typeof type}'`);
470
+ }
471
+
472
+ assert.isFunction(callback, 'success');
473
+ assert.isFunction(failure, 'failure');
474
+ assert.isFunction(progress, 'progress');
475
+
476
+ const assetDescription = new AssetDescription(path, type);
477
+
478
+ // requests made from inside an active load are recorded as dependencies of that load
479
+ const parent_pending = this.#find_enclosing_load(scope);
480
+
481
+ if (parent_pending !== null) {
482
+ parent_pending.addChild(assetDescription);
483
+ }
484
+
485
+ const asset = this.assets.get(assetDescription);
486
+
487
+ if (asset !== undefined) {
488
+
489
+ // already exists, dispatch callback immediately
490
+ callback(asset);
491
+
492
+ return;
493
+ }
494
+
495
+ // a request for an asset that is an ancestor of this request can never resolve
496
+ const cycle = this.#find_request_cycle(scope, assetDescription);
497
+
498
+ if (cycle !== null) {
499
+ const request = new AssetRequest(callback, failure, progress);
500
+
501
+ this.#schedule_response(request, new Error(`Cyclic asset request: ${cycle}`), false, assetDescription);
502
+
503
+ return;
504
+ }
505
+
506
+ //create request object
507
+ const assetRequest = new AssetRequest(callback, failure, progress);
508
+
509
+ assetRequest.scope = scope;
510
+ assetRequest.writeFlag(AssetRequestFlags.SkipQueue, skip_queue);
511
+
512
+ //submit request
513
+ this.submitRequest(assetDescription, assetRequest, parent_pending);
514
+ }
515
+
516
+ /**
517
+ * Checks if an asset is currently being loaded.
518
+ * Useful for avoiding redundant requests.
519
+ *
520
+ * @param {string} path
521
+ * @param {string} type
522
+ * @return {boolean}
523
+ */
524
+ isPending(path, type) {
525
+ const assetDescription = new AssetDescription(path, type);
526
+ return this.request_map.has(assetDescription);
527
+ }
528
+
529
+
530
+ /**
531
+ * Whether the most recent load attempt for the asset failed.
532
+ * Advisory only: a new {@link get} will still retry the load.
533
+ * @param {string} path
534
+ * @param {string} type
535
+ * @returns {boolean}
536
+ * @see isPending
537
+ */
538
+ isFailed(path, type) {
539
+ const ad = new AssetDescription(path, type);
540
+
541
+ return this.#failures.has(ad);
542
+ }
543
+
544
+ /**
545
+ * Checks if an asset is loaded.
546
+ * If the asset is loaded, calls to {@link tryGet} are guaranteed to succeed.
547
+ *
548
+ * @param {string} path
549
+ * @param {string} type
550
+ * @return {boolean}
551
+ */
552
+ isLoaded(path, type) {
553
+ const ad = new AssetDescription(path, type);
554
+
555
+ return this.assets.has(ad);
556
+ }
557
+
558
+ /**
559
+ * Same as {@link insert}, but will register the asset as pending until loader function resolves.
560
+ *
561
+ * NOTE: {@link AssetTransformer}s are not applied to the asset
562
+ *
563
+ * NOTE: any subsequent normal requests such as {@link get} will be routed to the same loader
564
+ *
565
+ * @template T
566
+ * @param {string} path
567
+ * @param {string} type
568
+ * @param {function(progress?:function(current:number, total:number)):Promise<Asset<T>>} loader
569
+ * @returns {Promise<Asset<T>>} loaded asset
570
+ * @see insert
571
+ * @example
572
+ * manager.insertAsync('path/to/asset', 'my-type', async (progress) => {
573
+ * const asset = await loadAssetFromNetwork('path/to/asset', 'type', progress);
574
+ * return asset;
575
+ * });
576
+ *
577
+ */
578
+ insertAsync(path, type, loader) {
579
+
580
+ const asset_descriptor = new AssetDescription(path, type);
581
+
582
+ if (this.request_map.get(asset_descriptor)) {
583
+ throw new Error(`Asset with path '${path}' and type '${type}' is already pending`);
584
+ }
585
+
586
+ const pending = new PendingAsset(asset_descriptor);
587
+
588
+ // resolution comes from the supplied loader function, there is nothing for the manager to dispatch
589
+ pending.dispatchable = false;
590
+
591
+ this.request_map.set(asset_descriptor, pending);
592
+
593
+ /**
594
+ *
595
+ * @param {number} current
596
+ * @param {number} total
597
+ */
598
+ const progress = (current, total) => {
599
+ pending.progress.setValue(current);
600
+ pending.progress.setUpperLimit(total);
601
+ };
602
+
603
+ let asset_promise;
604
+
605
+ try {
606
+ asset_promise = loader(progress);
607
+ } catch (e) {
608
+ this.request_map.delete(asset_descriptor);
609
+
610
+ // the deleted entry may have been the last outstanding work
611
+ this.#flush_drain_waiters();
612
+
613
+ throw e;
614
+ }
615
+
616
+ return asset_promise.then(asset => {
617
+ const existing = this.request_map.get(asset_descriptor);
618
+
619
+ if (existing !== pending) {
620
+ // looks like another resolution is pending, this completely invalidates current insersion request
621
+ // Likely reason is that something else was inserted later on
622
+ throw new Error(`Race condition. Asset with path '${path}' and type '${type}' was already resolved somewhere else.`);
623
+ }
624
+
625
+ this.insert(path, type, asset);
626
+
627
+ return asset;
628
+ }, error => {
629
+ const existing = this.request_map.get(asset_descriptor);
630
+
631
+ if (existing === pending) {
632
+ // deliver the failure to any requests that attached while the insertion was pending
633
+ pending.resolution_claimed = true;
634
+ this.#settle(pending, AssetLoadState.Failed, error);
635
+ }
636
+
637
+ //rethrow
638
+ throw error;
639
+ });
640
+ }
641
+
642
+ /**
643
+ * Manually add a fully resolved resource.
644
+ * If a load for the same description is in flight, it is squashed: the inserted asset wins,
645
+ * all accumulated requests are answered with it exactly once, and the loader's late resolution is dropped.
646
+ *
647
+ * NOTE: {@link AssetTransformer}s are not applied to the asset
648
+ *
649
+ * @template T
650
+ * @param {string} path
651
+ * @param {string} type
652
+ * @param {Asset<T>} asset
653
+ */
654
+ insert(path, type, asset) {
655
+ assert.isString(path, 'path');
656
+ assert.isString(type, 'type');
657
+ assert.isObject(asset, 'asset');
658
+
659
+ const asset_descriptor = new AssetDescription(path, type);
660
+
661
+ const existing_resource = this.assets.get(asset_descriptor);
662
+
663
+ if (existing_resource !== undefined && existing_resource !== asset) {
664
+ console.warn(`Another asset under ${asset_descriptor} already exists and will be replaced`);
665
+ }
666
+
667
+ // check for assets in-flight
668
+ const pending = this.request_map.get(asset_descriptor);
669
+
670
+ if (pending !== undefined) {
671
+ // squash the load in-flight: block the loader from claiming the resolution later
672
+ pending.resolution_claimed = true;
673
+
674
+ // if the load is still waiting in the queue there is no point dispatching it anymore
675
+ this.#pending_asset_wait_queue.delete(pending);
676
+
677
+ this.#settle(pending, AssetLoadState.Succeeded, asset);
678
+ } else {
679
+ // link asset description
680
+ asset.description = asset_descriptor;
681
+
682
+ // clear failures
683
+ this.#failures.delete(asset_descriptor);
684
+
685
+ this.assets.set(asset_descriptor, asset);
686
+ }
687
+ }
688
+
689
+ /**
690
+ *
691
+ * @param {Response} response
692
+ * @private
693
+ */
694
+ #process_response(response) {
695
+ const request = response.request;
696
+
697
+ if (response.success) {
698
+
699
+ try {
700
+ request.successCallback(response.value);
701
+ } catch (e) {
702
+ console.error(`Asset success callback raised an exception. AD:${response.description}`, e);
703
+ }
704
+
705
+ } else {
706
+
707
+ const failureCallback = request.failureCallback;
708
+
709
+ if (typeof failureCallback === "function") {
710
+ try {
711
+ failureCallback(response.value);
712
+ } catch (e) {
713
+ console.error(`Asset failure callback raised an exception. AD:${response.description}`, e);
714
+ }
715
+ } else {
716
+ //uncaught
717
+ console.error(`Uncaught asset load failure. AD:${response.description}`, response.value);
718
+ }
719
+
720
+ }
721
+ }
722
+
723
+ /**
724
+ *
725
+ * @param {AssetRequest} request
726
+ * @param {Asset|*} value
727
+ * @param {boolean} success
728
+ * @param {AssetDescription} description
729
+ * @private
730
+ */
731
+ #schedule_response(request, value, success, description) {
732
+ // technically you can schedule responses just fine, but commonly the user forgets to call 'startup' and so nothing happens which is perceived as a bug.
733
+ assert.equal(this.#is_running, true, 'AssetManager must be running to schedule responses');
734
+
735
+ this.#response_queue.add(new Response(request, value, success, description));
736
+
737
+ this.#wake_response_processor();
738
+ }
739
+
740
+ /**
741
+ *
742
+ * @param {PendingAsset} asset
743
+ * @private
744
+ */
745
+ #schedule_load(asset) {
746
+ if (this.#pending_asset_active_load_set.size < this.load_concurrency) {
747
+ this.#dispatch_pending_asset(asset);
748
+ } else {
749
+ asset.state = AssetLoadState.Queued;
750
+
751
+ this.#pending_asset_wait_queue.push(asset);
752
+ }
753
+ }
754
+
755
+ /**
756
+ * Force load of the asset
757
+ * @param {PendingAsset} asset
758
+ * @private
759
+ */
760
+ #force_load(asset) {
761
+ // externally resolved pending assets (see insertAsync) have no loader run to expedite
762
+ if (!asset.dispatchable) {
763
+ return;
764
+ }
765
+
766
+ // check if the asset is already being loaded
767
+ if (this.#pending_asset_active_load_set.has(asset)) {
768
+ return;
769
+ }
770
+
771
+ // remove from queue
772
+ this.#pending_asset_wait_queue.delete(asset);
773
+
774
+ // dispatch
775
+ this.#dispatch_pending_asset(asset);
776
+
777
+ }
778
+
779
+ /**
780
+ * Bookkeeping for a pending asset that reached a terminal state: de-register it everywhere
781
+ * and pull more work from the wait queue.
782
+ * @param {PendingAsset} pending_asset
783
+ * @private
784
+ */
785
+ #handle_asset_resolved(pending_asset) {
786
+ const active_set = this.#pending_asset_active_load_set;
787
+
788
+ // the map entry may already belong to a different pending asset (the load was squashed
789
+ // by an insert and a new request batch started since); only remove our own registration
790
+ if (this.request_map.get(pending_asset.description) === pending_asset) {
791
+ this.request_map.delete(pending_asset.description);
792
+ }
793
+
794
+ active_set.delete(pending_asset);
795
+
796
+ const dispatch_scope = pending_asset.dispatch_scope;
797
+
798
+ if (dispatch_scope !== null) {
799
+ this.#active_load_scopes.delete(dispatch_scope);
800
+ }
801
+
802
+ const queue = this.#pending_asset_wait_queue;
803
+
804
+ // schedule more if possible
805
+ while (!queue.isEmpty() && active_set.size < this.load_concurrency) {
806
+ const load = queue.pop();
807
+
808
+ this.#dispatch_pending_asset(load);
809
+ }
810
+ }
811
+
812
+ /**
813
+ * Single termination point for a pending asset. Exactly one resolution wins; the rest are dropped.
814
+ * All bookkeeping happens here, in a fixed order, before any requester callback is delivered.
815
+ * @param {PendingAsset} pendingAsset
816
+ * @param {AssetLoadState} state {@link AssetLoadState.Succeeded} or {@link AssetLoadState.Failed}
817
+ * @param {Asset|*} value loaded asset when succeeded, error otherwise
818
+ * @returns {boolean} false if the pending asset was already resolved and this resolution lost
819
+ * @private
820
+ */
821
+ #settle(pendingAsset, state, value) {
822
+ const current_state = pendingAsset.state;
823
+
824
+ if (current_state === AssetLoadState.Succeeded || current_state === AssetLoadState.Failed) {
825
+ console.warn(`Asset already resolved, late resolution dropped. AD:${pendingAsset.description}`);
826
+ return false;
827
+ }
828
+
829
+ pendingAsset.state = state;
830
+
831
+ const assetDescription = pendingAsset.description;
832
+
833
+ if (state === AssetLoadState.Succeeded) {
834
+ // link asset description
835
+ value.description = assetDescription;
836
+
837
+ // record dependencies gathered from nested requests made during the load
838
+ if (pendingAsset.children.length > 0) {
839
+ value.dependencies = pendingAsset.children;
840
+ }
841
+
842
+ // clear possible failure
843
+ this.#failures.delete(assetDescription);
844
+
845
+ // register asset
846
+ this.assets.set(assetDescription, value);
847
+ } else {
848
+ // record failure
849
+ this.#failures.add(assetDescription);
850
+ }
851
+
852
+ this.#handle_asset_resolved(pendingAsset);
853
+
854
+ // deliver responses
855
+ const requests = pendingAsset.requests;
856
+ const success = state === AssetLoadState.Succeeded;
857
+
858
+ for (let i = 0; i < requests.length; i++) {
859
+ this.#schedule_response(requests[i], value, success, assetDescription);
860
+ }
861
+
862
+ if (requests.length === 0) {
863
+ // nothing was scheduled for delivery (e.g. an insertAsync pending with no requesters),
864
+ // so the response processor will not run; this settle may have been the last outstanding work
865
+ this.#flush_drain_waiters();
866
+ }
867
+
868
+ return true;
869
+ }
870
+
871
+ /**
872
+ * Finalize a successful load: apply the transform chain, then settle.
873
+ * A broken transform chain fails the request instead of hanging it.
874
+ * @param {PendingAsset} pendingAsset
875
+ * @param {Asset} loaded_asset
876
+ * @returns {Promise<void>}
877
+ * @private
878
+ */
879
+ async #finalize_success(pendingAsset, loaded_asset) {
880
+ const assetDescription = pendingAsset.description;
881
+
882
+ let asset = loaded_asset;
883
+
884
+ try {
885
+ // apply the transform chain
886
+ const transformers = this.#transformers[assetDescription.type];
887
+
888
+ if (transformers !== undefined) {
889
+ const transformer_count = transformers.length;
890
+
891
+ for (let i = 0; i < transformer_count; i++) {
892
+ const transformer = transformers[i];
893
+
894
+ const transformed_asset = await transformer.transform(asset, assetDescription);
895
+
896
+ if (typeof transformed_asset !== "object" || transformed_asset === null) {
897
+ console.error('Transformer produced invalid result. Ignoring result.', transformer, assetDescription);
898
+ } else {
899
+ asset = transformed_asset;
900
+ }
901
+ }
902
+ }
903
+ } catch (e) {
904
+ this.#settle(pendingAsset, AssetLoadState.Failed, e);
905
+
906
+ return;
907
+ }
908
+
909
+ this.#settle(pendingAsset, AssetLoadState.Succeeded, asset);
910
+ }
911
+
912
+ /**
913
+ * Returns the in-flight load that the given request scope belongs to, or null if the scope
914
+ * does not descend from any active load (i.e. the request is top-level).
915
+ * @param {AssetRequestScope|null} scope
916
+ * @returns {PendingAsset|null}
917
+ * @private
918
+ */
919
+ #find_enclosing_load(scope) {
920
+ if (scope === null || this.#active_load_scopes.size === 0) {
921
+ return null;
922
+ }
923
+
924
+ const active = this.#active_load_scopes;
925
+
926
+ const visited = new Set();
927
+ const stack = [scope];
928
+
929
+ while (stack.length > 0) {
930
+ const s = stack.pop();
931
+
932
+ if (visited.has(s)) {
933
+ continue;
934
+ }
935
+
936
+ visited.add(s);
937
+
938
+ const pending = active.get(s);
939
+
940
+ if (pending !== undefined) {
941
+ return pending;
942
+ }
943
+
944
+ const sources = s.sources;
945
+ for (let i = 0; i < sources.length; i++) {
946
+ stack.push(sources[i]);
947
+ }
948
+ }
949
+
950
+ return null;
951
+ }
952
+
953
+ /**
954
+ * Detects a request for an asset that is itself an ancestor of the request (load cycle).
955
+ * @param {AssetRequestScope|null} scope
956
+ * @param {AssetDescription} description
957
+ * @returns {string|null} human-readable chain from the requested asset down to the requester, or null when there is no cycle
958
+ * @private
959
+ */
960
+ #find_request_cycle(scope, description) {
961
+ if (scope === null || this.#active_load_scopes.size === 0) {
962
+ return null;
963
+ }
964
+
965
+ const visited = new Set();
966
+
967
+ /**
968
+ *
969
+ * @param {AssetRequestScope} s
970
+ * @returns {AssetDescription[]|null}
971
+ */
972
+ function find(s) {
973
+ if (visited.has(s)) {
974
+ return null;
975
+ }
976
+
977
+ visited.add(s);
978
+
979
+ if (s.description !== null && s.description.equals(description)) {
980
+ return [s.description];
981
+ }
982
+
983
+ const sources = s.sources;
984
+ for (let i = 0; i < sources.length; i++) {
985
+ const chain = find(sources[i]);
986
+
987
+ if (chain !== null) {
988
+ if (s.description !== null) {
989
+ chain.push(s.description);
990
+ }
991
+
992
+ return chain;
993
+ }
994
+ }
995
+
996
+ return null;
997
+ }
998
+
999
+ // `find` builds the chain ancestor-first: [offender, ..., immediate parent]
1000
+ const chain = find(scope);
1001
+
1002
+ if (chain === null) {
1003
+ return null;
1004
+ }
1005
+
1006
+ chain.push(description);
1007
+
1008
+ return chain.join(' -> ');
1009
+ }
1010
+
1011
+ /**
1012
+ * Dispatch load request to relevant loader
1013
+ * @param {PendingAsset} pendingAsset
1014
+ * @private
1015
+ */
1016
+ #dispatch_pending_asset(pendingAsset) {
1017
+ const requests = pendingAsset.requests;
1018
+ const assetDescription = pendingAsset.description;
1019
+ const type = assetDescription.type;
1020
+ const path = assetDescription.path;
1021
+
1022
+ pendingAsset.state = AssetLoadState.Loading;
1023
+
1024
+ const loader = this.#loaders[type];
1025
+
1026
+ if (loader === undefined) {
1027
+ // no loader
1028
+ this.#settle(
1029
+ pendingAsset,
1030
+ AssetLoadState.Failed,
1031
+ new Error(`no loader exists for asset type '${type}', valid types are: ${Object.keys(this.#loaders).join(', ')}`)
1032
+ );
1033
+
1034
+ return;
1035
+ }
1036
+
1037
+ // mark as being loaded
1038
+ this.#pending_asset_active_load_set.add(pendingAsset);
1039
+
1040
+ // build the dispatch scope; it identifies this load for requests made by the loader (nested requests)
1041
+ const scope = new AssetRequestScope();
1042
+
1043
+ scope.description = assetDescription;
1044
+
1045
+ for (let i = 0; i < requests.length; i++) {
1046
+ const request_scope = requests[i].scope;
1047
+
1048
+ if (request_scope !== null) {
1049
+ array_push_if_unique(scope.sources, request_scope);
1050
+ }
1051
+ }
1052
+
1053
+ pendingAsset.dispatch_scope = scope;
1054
+ this.#active_load_scopes.set(scope, pendingAsset);
1055
+
1056
+ /**
1057
+ *
1058
+ * @param {Asset} loaded_asset
1059
+ */
1060
+ const success = (loaded_asset) => {
1061
+ if (pendingAsset.resolution_claimed) {
1062
+ console.warn(`Asset resolution already claimed, success invocation ignored. AD:${assetDescription}`);
1063
+ return;
1064
+ }
1065
+
1066
+ pendingAsset.resolution_claimed = true;
1067
+
1068
+ this.#finalize_success(pendingAsset, loaded_asset);
1069
+ }
1070
+
1071
+ const failure = (error) => {
1072
+ if (pendingAsset.resolution_claimed) {
1073
+ console.warn(`Asset resolution already claimed, failure invocation ignored. AD:${assetDescription}`);
1074
+ return;
1075
+ }
1076
+
1077
+ pendingAsset.resolution_claimed = true;
1078
+
1079
+ this.#settle(pendingAsset, AssetLoadState.Failed, error);
1080
+ }
1081
+
1082
+ function progress(current, total) {
1083
+ const request_count = requests.length;
1084
+
1085
+ for (let i = 0; i < request_count; i++) {
1086
+ const progressCallback = requests[i].progressCallback;
1087
+
1088
+ if (typeof progressCallback !== "function") {
1089
+ //progress callback is not a function, ignore
1090
+ continue;
1091
+ }
1092
+
1093
+ try {
1094
+ progressCallback(current, total);
1095
+ } catch (e) {
1096
+ console.error("Failed to execute asset progress callback", e);
1097
+ }
1098
+ }
1099
+
1100
+ pendingAsset.progress.setValue(current);
1101
+ pendingAsset.progress.setUpperLimit(total);
1102
+ }
1103
+
1104
+ try {
1105
+
1106
+ const result = loader.load(scope, path, success, failure, progress);
1107
+
1108
+ if (result instanceof Promise) {
1109
+ // allow promise responses
1110
+ result.catch(failure);
1111
+ }
1112
+
1113
+ } catch (e) {
1114
+ console.error(`Loader failed on invocation. path=${path}, type=${type}`, 'Loader exception: ', e);
1115
+ failure(e);
1116
+ }
1117
+ }
1118
+
1119
+ /**
1120
+ *
1121
+ * @param {AssetDescription} assetDescription
1122
+ * @param {AssetRequest} request
1123
+ * @param {PendingAsset|null} [parent_pending] the in-flight load this request was made from, if any
1124
+ * @private
1125
+ */
1126
+ submitRequest(assetDescription, request, parent_pending = null) {
1127
+ const requestMap = this.request_map;
1128
+
1129
+ let pendingAsset = requestMap.get(assetDescription);
1130
+
1131
+ const is_new = pendingAsset === undefined;
1132
+
1133
+ if (is_new) {
1134
+ pendingAsset = new PendingAsset(assetDescription);
1135
+ requestMap.set(assetDescription, pendingAsset);
1136
+ }
1137
+
1138
+ pendingAsset.requests.push(request);
1139
+
1140
+ // a nested request must not wait behind the concurrency limit: its parent occupies a
1141
+ // slot until this request resolves, so queueing it could deadlock
1142
+ const expedite = parent_pending !== null || request.getFlag(AssetRequestFlags.SkipQueue);
1143
+
1144
+ if (is_new) {
1145
+
1146
+ if (expedite) {
1147
+ this.#force_load(pendingAsset);
1148
+ } else {
1149
+ this.#schedule_load(pendingAsset);
1150
+ }
1151
+
1152
+ } else {
1153
+ // update priority queue if necessary
1154
+ this.#pending_asset_wait_queue.updateElementScore(pendingAsset);
1155
+
1156
+ if (expedite) {
1157
+ this.#force_load(pendingAsset);
1158
+ }
1159
+ }
1160
+ }
1161
+
1162
+
1163
+ /**
1164
+ *
1165
+ * @param {string} type
1166
+ * @return {boolean}
1167
+ */
1168
+ hasLoaderForType(type) {
1169
+ return this.getLoaderByType(type) !== undefined;
1170
+ }
1171
+
1172
+ /**
1173
+ *
1174
+ * @param {string} type
1175
+ * @returns {AssetLoader|undefined}
1176
+ */
1177
+ getLoaderByType(type) {
1178
+ assert.isString(type, 'type');
1179
+
1180
+ return this.#loaders[type];
1181
+ }
1182
+
1183
+ /**
1184
+ *
1185
+ * @param {string} type
1186
+ * @return {AssetDescription[]}
1187
+ * @private
1188
+ */
1189
+ #getLoadedAssetDescriptorsByType(type) {
1190
+ const loaded_assets = Array.from(this.assets.keys());
1191
+ return loaded_assets.filter(t => t.type === type);
1192
+ }
1193
+
1194
+ /**
1195
+ * Transformer will be applied to all assets of the given type in order of registration.
1196
+ *
1197
+ * Does not apply retroactively, assets that were already loaded will not be transformed.
1198
+ *
1199
+ * @template T
1200
+ * @param {string} type
1201
+ * @param {AssetTransformer<T>} transformer
1202
+ * @returns {void}
1203
+ * @see removeTransformer
1204
+ */
1205
+ registerTransformer(type, transformer) {
1206
+ let transformers = this.#transformers[type];
1207
+
1208
+ if (transformers === undefined) {
1209
+ transformers = [];
1210
+
1211
+ this.#transformers[type] = transformers;
1212
+ }
1213
+
1214
+ transformers.push(transformer);
1215
+
1216
+ // check for loaded assets
1217
+ const matching_assets = this.#getLoadedAssetDescriptorsByType(type);
1218
+
1219
+ if (matching_assets.length > 0) {
1220
+ console.warn(`Following assets of matching type '${type}' are already loaded and transform is not applied to them:\n\t${matching_assets.join('\n\t')}`);
1221
+ }
1222
+
1223
+ }
1224
+
1225
+ /**
1226
+ * @template T
1227
+ * @param {string} type
1228
+ * @param {AssetTransformer<T>} transformer
1229
+ * @returns {boolean} true if removed, false if not found
1230
+ * @see registerTransformer
1231
+ */
1232
+ unregisterTransformer(type, transformer) {
1233
+
1234
+ const transformers = this.#transformers[type];
1235
+
1236
+ if (transformers === undefined) {
1237
+ // not found
1238
+ return false;
1239
+ }
1240
+
1241
+ if (!array_remove_first(transformers, transformer)) {
1242
+ // not found
1243
+ return false;
1244
+ }
1245
+
1246
+ // check for loaded assets
1247
+ const matching_assets = this.#getLoadedAssetDescriptorsByType(type);
1248
+
1249
+ if (matching_assets.length > 0) {
1250
+ console.warn(`Following assets of matching type '${type}' are already loaded and transform was probably already applied to them:\n\t${matching_assets.join('\n\t')}`);
1251
+ }
1252
+
1253
+ return true;
1254
+ }
1255
+
1256
+ /**
1257
+ * Will register loader only if none exists for this type
1258
+ * @template T
1259
+ * @param {string} type
1260
+ * @param {AssetLoader<T>} loader
1261
+ * @returns {Promise<boolean>} true if registered, false otherwise
1262
+ */
1263
+ async tryRegisterLoader(type, loader) {
1264
+ if (this.hasLoaderForType(type)) {
1265
+ return false;
1266
+ }
1267
+
1268
+ await this.registerLoader(type, loader);
1269
+
1270
+ return true;
1271
+ }
1272
+
1273
+ /**
1274
+ * @template T
1275
+ * @param {string} type
1276
+ * @param {AssetLoader<T>} loader
1277
+ * @throws {Error} if a loader is already registered for the given type
1278
+ */
1279
+ async registerLoader(type, loader) {
1280
+ assert.isString(type, 'type');
1281
+
1282
+ const existing_loader = this.getLoaderByType(type);
1283
+
1284
+ if (existing_loader !== undefined) {
1285
+ if (existing_loader === loader) {
1286
+ // all is well, already registered
1287
+ return existing_loader;
1288
+ } else if (Object.getPrototypeOf(existing_loader) === Object.getPrototypeOf(loader)) {
1289
+ console.warn(`Another instance of this loader is already registered for type '${type}'. Ignoring.`);
1290
+ return existing_loader;
1291
+ } else {
1292
+ throw new Error(`Loader for type '${type}' is already registered`);
1293
+ }
1294
+ }
1295
+
1296
+
1297
+ let _loader = loader;
1298
+
1299
+ if (typeof _loader === "function") {
1300
+
1301
+ // legacy function-based loader with signature (path, success, failure, progress):
1302
+ // adapt to the AssetLoader contract, resolving the network path on its behalf
1303
+ _loader = new AssetLoader();
1304
+ _loader.load = (scope, path, success, failure, progress) => loader(this.resolveNetworkPath(path), success, failure, progress);
1305
+
1306
+ console.warn(`function-based loaders are deprecated (${type})`);
1307
+
1308
+ }
1309
+
1310
+ await _loader.link(this, this.#context);
1311
+
1312
+ this.#loaders[type] = _loader;
1313
+
1314
+ return _loader;
1315
+ }
1316
+
1317
+ /**
1318
+ *
1319
+ * @param {string} type
1320
+ */
1321
+ async unregisterLoader(type) {
1322
+ const loader = this.getLoaderByType(type);
1323
+
1324
+ if (loader === undefined) {
1325
+ // asset loader is not registered, nothing to do
1326
+ return;
1327
+
1328
+ }
1329
+
1330
+ // first remove the loader from registry so no further asset requests can be made
1331
+ delete this.#loaders[type];
1332
+
1333
+ // TODO address all pending requests, possibly waiting for all of them to finalize
1334
+
1335
+ // finally unlink the loader
1336
+ await loader.unlink();
1337
+ }
1338
+
1339
+ /**
1340
+ * Retrieve an asset if it is loaded, returns null if the asset is not loaded.
1341
+ * Does not trigger loading if the asset is not loaded.
1342
+ * @template T
1343
+ * @param {String} path
1344
+ * @param {String} type
1345
+ * @returns {Asset<T>|null}
1346
+ */
1347
+ tryGet(path, type) {
1348
+ const assetDescription = new AssetDescription(path, type);
1349
+
1350
+ const asset = this.assets.get(assetDescription);
1351
+
1352
+ if (asset !== undefined) {
1353
+ return asset;
1354
+ } else {
1355
+ return null;
1356
+ }
1357
+ }
1358
+
1359
+ /**
1360
+ * @template T
1361
+ * @param {string} alias
1362
+ * @return {Promise<Asset<T>>}
1363
+ */
1364
+ promiseByAlias(alias) {
1365
+ assert.isString(alias, 'alias');
1366
+
1367
+ // resolve alias
1368
+ const assetDescription = this.#aliases.get(alias);
1369
+
1370
+ if (assetDescription === undefined) {
1371
+ return Promise.reject(new Error(`Alias '${alias}' not found`));
1372
+ }
1373
+
1374
+ return this.promise(assetDescription.path, assetDescription.type);
1375
+ }
1376
+
1377
+ /**
1378
+ *
1379
+ * @param {string} alias
1380
+ * @return {AssetDescription|undefined}
1381
+ */
1382
+ resolveAlias(alias) {
1383
+
1384
+ // todo consider cloning result to protect against mutation
1385
+
1386
+ return this.#aliases.get(alias);
1387
+
1388
+ }
1389
+
1390
+ /**
1391
+ *
1392
+ * @param {string} alias
1393
+ * @param {string} path
1394
+ * @param {string} type
1395
+ */
1396
+ assignAlias(alias, path, type) {
1397
+ assert.isString(alias, 'alias');
1398
+ assert.isString(path, 'path');
1399
+ assert.isString(type, 'type');
1400
+
1401
+ const assetDescription = new AssetDescription(path, type);
1402
+
1403
+ this.#aliases.set(alias, assetDescription);
1404
+ }
1405
+ }
1406
+
1407
+ /**
1408
+ * @readonly
1409
+ * @type {boolean}
1410
+ */
1411
+ AssetManager.prototype.isAssetManager = true;