@woosh/meep-engine 3.64.0 → 3.65.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 (370) hide show
  1. package/CHANGELOG.md +85 -0
  2. package/build/bundle-worker-image-decoder.js +1 -1
  3. package/build/bundle-worker-terrain.js +1 -1
  4. package/package.json +1 -1
  5. package/src/core/binary/BinaryBuffer.d.ts +5 -0
  6. package/src/core/binary/BinaryBuffer.d.ts.map +1 -1
  7. package/src/core/binary/BinaryBuffer.js +39 -5
  8. package/src/core/geom/3d/topology/struct/binary/io/bt_boundary_loop.d.ts +65 -6
  9. package/src/core/geom/3d/topology/struct/binary/io/bt_boundary_loop.d.ts.map +1 -1
  10. package/src/core/geom/3d/topology/struct/binary/io/bt_boundary_loop.js +451 -101
  11. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.d.ts +4 -2
  12. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.d.ts.map +1 -1
  13. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.js +4 -2
  14. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.d.ts +8 -1
  15. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.d.ts.map +1 -1
  16. package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.js +45 -10
  17. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.d.ts.map +1 -1
  18. package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.js +237 -119
  19. package/src/engine/graphics/ecs/grass/GrassSpecies.d.ts +143 -0
  20. package/src/engine/graphics/ecs/grass/GrassSpecies.d.ts.map +1 -0
  21. package/src/engine/graphics/ecs/grass/GrassSpecies.js +189 -0
  22. package/src/engine/graphics/ecs/grass/GrassSurface.d.ts +25 -0
  23. package/src/engine/graphics/ecs/grass/GrassSurface.d.ts.map +1 -0
  24. package/src/engine/graphics/ecs/grass/GrassSurface.js +32 -0
  25. package/src/engine/graphics/ecs/grass/GroundCover.d.ts +68 -0
  26. package/src/engine/graphics/ecs/grass/GroundCover.d.ts.map +1 -0
  27. package/src/engine/graphics/ecs/grass/GroundCover.js +85 -0
  28. package/src/engine/graphics/texture/sampler/exr_to_sampler2d.d.ts +27 -0
  29. package/src/engine/graphics/texture/sampler/exr_to_sampler2d.d.ts.map +1 -0
  30. package/src/engine/graphics/texture/sampler/exr_to_sampler2d.js +91 -0
  31. package/src/engine/graphics/texture/sampler/sampler2d_to_exr.d.ts +23 -0
  32. package/src/engine/graphics/texture/sampler/sampler2d_to_exr.d.ts.map +1 -0
  33. package/src/engine/graphics/texture/sampler/sampler2d_to_exr.js +64 -0
  34. package/src/engine/graphics3/GrassSurfaceSystem.d.ts +153 -0
  35. package/src/engine/graphics3/GrassSurfaceSystem.d.ts.map +1 -0
  36. package/src/engine/graphics3/GrassSurfaceSystem.js +1076 -0
  37. package/src/engine/graphics3/GroundCoverSystem.d.ts +33 -0
  38. package/src/engine/graphics3/GroundCoverSystem.d.ts.map +1 -0
  39. package/src/engine/graphics3/GroundCoverSystem.js +58 -0
  40. package/src/engine/network/NetworkSession.d.ts.map +1 -1
  41. package/src/engine/network/NetworkSession.js +372 -110
  42. package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
  43. package/src/engine/network/orchestrator/NetworkPeer.js +6 -1
  44. package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts.map +1 -1
  45. package/src/engine/network/orchestrator/ServerAuthoritativeClient.js +9 -2
  46. package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts.map +1 -1
  47. package/src/engine/network/orchestrator/ServerAuthoritativeServer.js +325 -140
  48. package/src/engine/network/sim/SimActionExecutor.d.ts +4 -1
  49. package/src/engine/network/sim/SimActionExecutor.d.ts.map +1 -1
  50. package/src/engine/network/sim/SimActionExecutor.js +65 -9
  51. package/src/engine/network/state/PredictionHistory.d.ts.map +1 -1
  52. package/src/engine/network/state/PredictionHistory.js +6 -1
  53. package/src/engine/network/time/AdaptiveRenderDelay.d.ts +25 -14
  54. package/src/engine/network/time/AdaptiveRenderDelay.d.ts.map +1 -1
  55. package/src/engine/network/time/AdaptiveRenderDelay.js +38 -20
  56. package/src/engine/network/time/RenderPlayout.d.ts +23 -3
  57. package/src/engine/network/time/RenderPlayout.d.ts.map +1 -1
  58. package/src/engine/network/time/RenderPlayout.js +40 -4
  59. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  60. package/src/engine/physics/fluid/obstacle/chunk_fluid_obstacle_record.d.ts +5 -1
  61. package/src/engine/physics/fluid/obstacle/chunk_fluid_obstacle_record.d.ts.map +1 -1
  62. package/src/engine/physics/fluid/obstacle/chunk_fluid_obstacle_record.js +27 -1
  63. package/src/format/image/exr/ExrCompression.d.ts +22 -0
  64. package/src/format/image/exr/ExrCompression.d.ts.map +1 -0
  65. package/src/format/image/exr/ExrCompression.js +27 -0
  66. package/src/format/image/exr/ExrImage.d.ts +32 -0
  67. package/src/format/image/exr/ExrImage.d.ts.map +1 -0
  68. package/src/format/image/exr/ExrImage.js +32 -0
  69. package/src/format/image/exr/ExrPixelType.d.ts +13 -0
  70. package/src/format/image/exr/ExrPixelType.d.ts.map +1 -0
  71. package/src/format/image/exr/ExrPixelType.js +18 -0
  72. package/src/format/image/exr/exr_compare_names.d.ts +16 -0
  73. package/src/format/image/exr/exr_compare_names.d.ts.map +1 -0
  74. package/src/format/image/exr/exr_compare_names.js +25 -0
  75. package/src/format/image/exr/exr_constants.d.ts +49 -0
  76. package/src/format/image/exr/exr_constants.d.ts.map +1 -0
  77. package/src/format/image/exr/exr_constants.js +56 -0
  78. package/src/format/image/exr/exr_read.d.ts +32 -0
  79. package/src/format/image/exr/exr_read.d.ts.map +1 -0
  80. package/src/format/image/exr/exr_read.js +531 -0
  81. package/src/format/image/exr/exr_sample_bits.d.ts +16 -0
  82. package/src/format/image/exr/exr_sample_bits.d.ts.map +1 -0
  83. package/src/format/image/exr/exr_sample_bits.js +21 -0
  84. package/src/format/image/exr/exr_scanlines_per_chunk.d.ts +17 -0
  85. package/src/format/image/exr/exr_scanlines_per_chunk.d.ts.map +1 -0
  86. package/src/format/image/exr/exr_scanlines_per_chunk.js +31 -0
  87. package/src/format/image/exr/exr_write.d.ts +27 -0
  88. package/src/format/image/exr/exr_write.d.ts.map +1 -0
  89. package/src/format/image/exr/exr_write.js +378 -0
  90. package/src/shade/device/shader/ShaderModuleCompiler.d.ts +2 -0
  91. package/src/shade/device/shader/ShaderModuleCompiler.d.ts.map +1 -1
  92. package/src/shade/device/shader/ShaderModuleCompiler.js +25 -2
  93. package/src/shade/playground/grass_surfaces/index.html +75 -0
  94. package/src/shade/playground/grass_surfaces/main.d.ts +2 -0
  95. package/src/shade/playground/grass_surfaces/main.d.ts.map +1 -0
  96. package/src/shade/playground/grass_surfaces/main.js +593 -0
  97. package/src/shade/playground/grass_surfaces/read_grass_surfaces.d.ts +62 -0
  98. package/src/shade/playground/grass_surfaces/read_grass_surfaces.d.ts.map +1 -0
  99. package/src/shade/playground/grass_surfaces/read_grass_surfaces.js +188 -0
  100. package/src/shade/playground/probe_clipmap/index.html +5 -0
  101. package/src/shade/playground/probe_clipmap/main.d.ts.map +1 -1
  102. package/src/shade/playground/probe_clipmap/main.js +34 -1
  103. package/src/shade/playground/probe_clipmap_box/README.md +5 -1
  104. package/src/shade/playground/probe_clipmap_box/index.html +12 -0
  105. package/src/shade/playground/probe_clipmap_box/main.d.ts.map +1 -1
  106. package/src/shade/playground/probe_clipmap_box/main.js +15 -0
  107. package/src/shade/playground/probe_clipmap_box/scene.d.ts +8 -1
  108. package/src/shade/playground/probe_clipmap_box/scene.d.ts.map +1 -1
  109. package/src/shade/playground/probe_clipmap_box/scene.js +74 -6
  110. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  111. package/src/shade/renderer/Renderer.js +47 -43
  112. package/src/shade/renderer/extension/ViewTextures.d.ts +12 -5
  113. package/src/shade/renderer/extension/ViewTextures.d.ts.map +1 -1
  114. package/src/shade/renderer/extension/ViewTextures.js +19 -5
  115. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +3 -1
  116. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts.map +1 -1
  117. package/src/shade/renderer/fluid/GPUFluidCascadeStack.js +6 -1
  118. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +7 -0
  119. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts.map +1 -1
  120. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.js +10 -0
  121. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +7 -1
  122. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts.map +1 -1
  123. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +46 -15
  124. package/src/shade/renderer/geometry/sdf/bundle/ModelCacheBundle.d.ts +3 -2
  125. package/src/shade/renderer/geometry/sdf/bundle/ModelCacheBundle.d.ts.map +1 -1
  126. package/src/shade/renderer/geometry/sdf/bundle/ModelCacheBundle.js +3 -2
  127. package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_sort_morton.d.ts +22 -0
  128. package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_sort_morton.d.ts.map +1 -0
  129. package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_sort_morton.js +247 -0
  130. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts +50 -0
  131. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
  132. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +101 -0
  133. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts +2 -1
  134. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts.map +1 -1
  135. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.js +2 -1
  136. package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.d.ts +8 -0
  137. package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.d.ts.map +1 -1
  138. package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.js +12 -0
  139. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.d.ts +12 -6
  140. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.d.ts.map +1 -1
  141. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.js +35 -29
  142. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_clipmap.d.ts.map +1 -1
  143. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_clipmap.js +4 -2
  144. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_material.d.ts.map +1 -1
  145. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_material.js +6 -4
  146. package/src/shade/renderer/global_illumination/probe_clipmap/material/GPUBrickMaterial.d.ts.map +1 -1
  147. package/src/shade/renderer/global_illumination/probe_clipmap/material/GPUBrickMaterial.js +2 -1
  148. package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material.d.ts +6 -5
  149. package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material.d.ts.map +1 -1
  150. package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material.js +15 -14
  151. package/src/shade/renderer/global_illumination/probe_clipmap/material/shader_brick_material_gather.d.ts.map +1 -1
  152. package/src/shade/renderer/global_illumination/probe_clipmap/material/shader_brick_material_gather.js +4 -2
  153. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +19 -2
  154. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
  155. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +128 -10
  156. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts +19 -13
  157. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts.map +1 -1
  158. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.js +27 -15
  159. package/src/shade/renderer/global_illumination/probe_clipmap/probe/ProbeClipmapScreenWants.d.ts +19 -11
  160. package/src/shade/renderer/global_illumination/probe_clipmap/probe/ProbeClipmapScreenWants.d.ts.map +1 -1
  161. package/src/shade/renderer/global_illumination/probe_clipmap/probe/ProbeClipmapScreenWants.js +35 -11
  162. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts +3 -3
  163. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts.map +1 -1
  164. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.js +18 -14
  165. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_box_cages.d.ts +40 -0
  166. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_box_cages.d.ts.map +1 -0
  167. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_box_cages.js +174 -0
  168. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_material.d.ts +4 -4
  169. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_material.js +10 -10
  170. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_parallax.d.ts +31 -0
  171. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_parallax.d.ts.map +1 -0
  172. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_parallax.js +54 -0
  173. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts +8 -4
  174. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts.map +1 -1
  175. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.js +10 -21
  176. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.d.ts +7 -2
  177. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.d.ts.map +1 -1
  178. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.js +33 -29
  179. package/src/shade/renderer/global_illumination/probe_clipmap/probe/graph_probe_clipmap_want_meshlets.d.ts +28 -0
  180. package/src/shade/renderer/global_illumination/probe_clipmap/probe/graph_probe_clipmap_want_meshlets.d.ts.map +1 -0
  181. package/src/shade/renderer/global_illumination/probe_clipmap/probe/graph_probe_clipmap_want_meshlets.js +138 -0
  182. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts +7 -3
  183. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.d.ts.map +1 -1
  184. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_accumulate.js +28 -17
  185. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.d.ts +13 -9
  186. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.d.ts.map +1 -1
  187. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.js +18 -11
  188. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_light.js +1 -1
  189. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_project.d.ts +18 -18
  190. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_project.d.ts.map +1 -1
  191. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_project.js +44 -48
  192. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_relocate.d.ts.map +1 -1
  193. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_relocate.js +4 -2
  194. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_retire.d.ts.map +1 -1
  195. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_retire.js +2 -3
  196. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_schedule.d.ts +5 -3
  197. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_schedule.d.ts.map +1 -1
  198. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_schedule.js +15 -30
  199. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.js +1 -1
  200. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.d.ts.map +1 -1
  201. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.js +4 -2
  202. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.d.ts +11 -0
  203. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.d.ts.map +1 -1
  204. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.js +29 -2
  205. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_late.d.ts +40 -0
  206. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_late.d.ts.map +1 -0
  207. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_late.js +126 -0
  208. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_meshlets.d.ts +36 -0
  209. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_meshlets.d.ts.map +1 -0
  210. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_meshlets.js +221 -0
  211. package/src/shade/renderer/gpu_primitive/age_eviction/chunk_age_eviction.d.ts +40 -0
  212. package/src/shade/renderer/gpu_primitive/age_eviction/chunk_age_eviction.d.ts.map +1 -0
  213. package/src/shade/renderer/gpu_primitive/age_eviction/chunk_age_eviction.js +86 -0
  214. package/src/shade/renderer/grass/blade/GPUGrassBlades.d.ts +135 -0
  215. package/src/shade/renderer/grass/blade/GPUGrassBlades.d.ts.map +1 -0
  216. package/src/shade/renderer/grass/blade/GPUGrassBlades.js +676 -0
  217. package/src/shade/renderer/grass/blade/GRASS_BLADE.d.ts +145 -0
  218. package/src/shade/renderer/grass/blade/GRASS_BLADE.d.ts.map +1 -0
  219. package/src/shade/renderer/grass/blade/GRASS_BLADE.js +179 -0
  220. package/src/shade/renderer/grass/blade/chunk_grass_blade.d.ts +63 -0
  221. package/src/shade/renderer/grass/blade/chunk_grass_blade.d.ts.map +1 -0
  222. package/src/shade/renderer/grass/blade/chunk_grass_blade.js +244 -0
  223. package/src/shade/renderer/grass/blade/chunk_grass_blade_wind.d.ts +58 -0
  224. package/src/shade/renderer/grass/blade/chunk_grass_blade_wind.d.ts.map +1 -0
  225. package/src/shade/renderer/grass/blade/chunk_grass_blade_wind.js +174 -0
  226. package/src/shade/renderer/grass/blade/grass_blade_id_draw.d.ts +25 -0
  227. package/src/shade/renderer/grass/blade/grass_blade_id_draw.d.ts.map +1 -0
  228. package/src/shade/renderer/grass/blade/grass_blade_id_draw.js +133 -0
  229. package/src/shade/renderer/grass/blade/grass_blade_mechanics.d.ts +80 -0
  230. package/src/shade/renderer/grass/blade/grass_blade_mechanics.d.ts.map +1 -0
  231. package/src/shade/renderer/grass/blade/grass_blade_mechanics.js +92 -0
  232. package/src/shade/renderer/grass/blade/grass_blade_resolve.d.ts +29 -0
  233. package/src/shade/renderer/grass/blade/grass_blade_resolve.d.ts.map +1 -0
  234. package/src/shade/renderer/grass/blade/grass_blade_resolve.js +175 -0
  235. package/src/shade/renderer/grass/blade/shader_grass_blade_draw_args.d.ts +14 -0
  236. package/src/shade/renderer/grass/blade/shader_grass_blade_draw_args.d.ts.map +1 -0
  237. package/src/shade/renderer/grass/blade/shader_grass_blade_draw_args.js +45 -0
  238. package/src/shade/renderer/grass/blade/shader_grass_blade_expand.d.ts +61 -0
  239. package/src/shade/renderer/grass/blade/shader_grass_blade_expand.d.ts.map +1 -0
  240. package/src/shade/renderer/grass/blade/shader_grass_blade_expand.js +340 -0
  241. package/src/shade/renderer/grass/blade/shader_grass_cell_count.d.ts +46 -0
  242. package/src/shade/renderer/grass/blade/shader_grass_cell_count.d.ts.map +1 -0
  243. package/src/shade/renderer/grass/blade/shader_grass_cell_count.js +280 -0
  244. package/src/shade/renderer/grass/population/chunk_grass_population.d.ts +60 -0
  245. package/src/shade/renderer/grass/population/chunk_grass_population.d.ts.map +1 -0
  246. package/src/shade/renderer/grass/population/chunk_grass_population.js +171 -0
  247. package/src/shade/renderer/grass/press/GPUGrassPress.d.ts +99 -0
  248. package/src/shade/renderer/grass/press/GPUGrassPress.d.ts.map +1 -0
  249. package/src/shade/renderer/grass/press/GPUGrassPress.js +436 -0
  250. package/src/shade/renderer/grass/press/GRASS_PRESS.d.ts +179 -0
  251. package/src/shade/renderer/grass/press/GRASS_PRESS.d.ts.map +1 -0
  252. package/src/shade/renderer/grass/press/GRASS_PRESS.js +217 -0
  253. package/src/shade/renderer/grass/press/chunk_grass_press.d.ts +65 -0
  254. package/src/shade/renderer/grass/press/chunk_grass_press.d.ts.map +1 -0
  255. package/src/shade/renderer/grass/press/chunk_grass_press.js +296 -0
  256. package/src/shade/renderer/grass/press/shader_grass_press_mark.d.ts +31 -0
  257. package/src/shade/renderer/grass/press/shader_grass_press_mark.d.ts.map +1 -0
  258. package/src/shade/renderer/grass/press/shader_grass_press_mark.js +169 -0
  259. package/src/shade/renderer/grass/press/shader_grass_press_stamp.d.ts +27 -0
  260. package/src/shade/renderer/grass/press/shader_grass_press_stamp.d.ts.map +1 -0
  261. package/src/shade/renderer/grass/press/shader_grass_press_stamp.js +183 -0
  262. package/src/shade/renderer/grass/surface/GPUGrassSurfaces.d.ts +193 -0
  263. package/src/shade/renderer/grass/surface/GPUGrassSurfaces.d.ts.map +1 -0
  264. package/src/shade/renderer/grass/surface/GPUGrassSurfaces.js +1253 -0
  265. package/src/shade/renderer/grass/surface/GRASS_SURFACE.d.ts +211 -0
  266. package/src/shade/renderer/grass/surface/GRASS_SURFACE.d.ts.map +1 -0
  267. package/src/shade/renderer/grass/surface/GRASS_SURFACE.js +241 -0
  268. package/src/shade/renderer/grass/surface/GRASS_SURFACE_VIEW.d.ts +82 -0
  269. package/src/shade/renderer/grass/surface/GRASS_SURFACE_VIEW.d.ts.map +1 -0
  270. package/src/shade/renderer/grass/surface/GRASS_SURFACE_VIEW.js +111 -0
  271. package/src/shade/renderer/grass/surface/chunk_grass_column_cross.d.ts +39 -0
  272. package/src/shade/renderer/grass/surface/chunk_grass_column_cross.d.ts.map +1 -0
  273. package/src/shade/renderer/grass/surface/chunk_grass_column_cross.js +85 -0
  274. package/src/shade/renderer/grass/surface/chunk_grass_directory.d.ts +29 -0
  275. package/src/shade/renderer/grass/surface/chunk_grass_directory.d.ts.map +1 -0
  276. package/src/shade/renderer/grass/surface/chunk_grass_directory.js +112 -0
  277. package/src/shade/renderer/grass/surface/chunk_grass_slot.d.ts +27 -0
  278. package/src/shade/renderer/grass/surface/chunk_grass_slot.d.ts.map +1 -0
  279. package/src/shade/renderer/grass/surface/chunk_grass_slot.js +50 -0
  280. package/src/shade/renderer/grass/surface/chunk_grass_surface_frame.d.ts +21 -0
  281. package/src/shade/renderer/grass/surface/chunk_grass_surface_frame.d.ts.map +1 -0
  282. package/src/shade/renderer/grass/surface/chunk_grass_surface_frame.js +41 -0
  283. package/src/shade/renderer/grass/surface/chunk_grass_surface_window.d.ts +32 -0
  284. package/src/shade/renderer/grass/surface/chunk_grass_surface_window.d.ts.map +1 -0
  285. package/src/shade/renderer/grass/surface/chunk_grass_surface_window.js +136 -0
  286. package/src/shade/renderer/grass/surface/chunk_grass_surfel.d.ts +37 -0
  287. package/src/shade/renderer/grass/surface/chunk_grass_surfel.d.ts.map +1 -0
  288. package/src/shade/renderer/grass/surface/chunk_grass_surfel.js +85 -0
  289. package/src/shade/renderer/grass/surface/chunk_grass_tile.d.ts +25 -0
  290. package/src/shade/renderer/grass/surface/chunk_grass_tile.d.ts.map +1 -0
  291. package/src/shade/renderer/grass/surface/chunk_grass_tile.js +52 -0
  292. package/src/shade/renderer/grass/surface/shader_grass_directory_fill.d.ts +23 -0
  293. package/src/shade/renderer/grass/surface/shader_grass_directory_fill.d.ts.map +1 -0
  294. package/src/shade/renderer/grass/surface/shader_grass_directory_fill.js +87 -0
  295. package/src/shade/renderer/grass/surface/shader_grass_surface_bake.d.ts +43 -0
  296. package/src/shade/renderer/grass/surface/shader_grass_surface_bake.d.ts.map +1 -0
  297. package/src/shade/renderer/grass/surface/shader_grass_surface_bake.js +265 -0
  298. package/src/shade/renderer/grass/surface/shader_grass_surface_bake_command.d.ts +13 -0
  299. package/src/shade/renderer/grass/surface/shader_grass_surface_bake_command.d.ts.map +1 -0
  300. package/src/shade/renderer/grass/surface/shader_grass_surface_bake_command.js +49 -0
  301. package/src/shade/renderer/grass/surface/shader_grass_surface_invalidate.d.ts +62 -0
  302. package/src/shade/renderer/grass/surface/shader_grass_surface_invalidate.d.ts.map +1 -0
  303. package/src/shade/renderer/grass/surface/shader_grass_surface_invalidate.js +162 -0
  304. package/src/shade/renderer/grass/surface/shader_grass_surface_retire.d.ts +40 -0
  305. package/src/shade/renderer/grass/surface/shader_grass_surface_retire.d.ts.map +1 -0
  306. package/src/shade/renderer/grass/surface/shader_grass_surface_retire.js +155 -0
  307. package/src/shade/renderer/grass/surface/shader_grass_surface_schedule.d.ts +19 -0
  308. package/src/shade/renderer/grass/surface/shader_grass_surface_schedule.d.ts.map +1 -0
  309. package/src/shade/renderer/grass/surface/shader_grass_surface_schedule.js +58 -0
  310. package/src/shade/renderer/grass/surface/shader_grass_surface_want.d.ts +30 -0
  311. package/src/shade/renderer/grass/surface/shader_grass_surface_want.d.ts.map +1 -0
  312. package/src/shade/renderer/grass/surface/shader_grass_surface_want.js +251 -0
  313. package/src/shade/renderer/grass/surface/shader_grass_surface_window_count.d.ts +21 -0
  314. package/src/shade/renderer/grass/surface/shader_grass_surface_window_count.d.ts.map +1 -0
  315. package/src/shade/renderer/grass/surface/shader_grass_surface_window_count.js +75 -0
  316. package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.d.ts.map +1 -1
  317. package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.js +4 -23
  318. package/src/shade/renderer/postprocess/velocity/view_velocity_matrices.d.ts +12 -0
  319. package/src/shade/renderer/postprocess/velocity/view_velocity_matrices.d.ts.map +1 -0
  320. package/src/shade/renderer/postprocess/velocity/view_velocity_matrices.js +29 -0
  321. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts.map +1 -1
  322. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +22 -0
  323. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  324. package/src/shade/renderer/scene/GPUSceneContext.js +3 -0
  325. package/src/shade/renderer/scene/GRASS_SURFACE_PARAMS_STRUCT.d.ts +27 -0
  326. package/src/shade/renderer/scene/GRASS_SURFACE_PARAMS_STRUCT.d.ts.map +1 -0
  327. package/src/shade/renderer/scene/GRASS_SURFACE_PARAMS_STRUCT.js +38 -0
  328. package/src/shade/renderer/scene/MESH_GROUND_COVER_STRUCT.d.ts +28 -0
  329. package/src/shade/renderer/scene/MESH_GROUND_COVER_STRUCT.d.ts.map +1 -0
  330. package/src/shade/renderer/scene/MESH_GROUND_COVER_STRUCT.js +58 -0
  331. package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.d.ts.map +1 -1
  332. package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.js +8 -0
  333. package/src/shade/renderer/shader/chunk/filter/chunk_multiscale_mean.d.ts +8 -0
  334. package/src/shade/renderer/shader/chunk/filter/chunk_multiscale_mean.d.ts.map +1 -1
  335. package/src/shade/renderer/shader/chunk/filter/chunk_multiscale_mean.js +21 -3
  336. package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_nearest_among.d.ts +37 -0
  337. package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_nearest_among.d.ts.map +1 -0
  338. package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_nearest_among.js +148 -0
  339. package/src/shade/renderer/shader/chunk/sdf/chunk_shape_record_line_span.d.ts +20 -0
  340. package/src/shade/renderer/shader/chunk/sdf/chunk_shape_record_line_span.d.ts.map +1 -0
  341. package/src/shade/renderer/shader/chunk/sdf/chunk_shape_record_line_span.js +169 -0
  342. package/src/shade/renderer/texture/atlas/chunk_tile_atlas_slot_origin.d.ts +18 -0
  343. package/src/shade/renderer/texture/atlas/chunk_tile_atlas_slot_origin.d.ts.map +1 -1
  344. package/src/shade/renderer/texture/atlas/chunk_tile_atlas_slot_origin.js +28 -0
  345. package/src/shade/renderer/texture/atlas/tile_atlas_slot_shift.d.ts +13 -0
  346. package/src/shade/renderer/texture/atlas/tile_atlas_slot_shift.d.ts.map +1 -0
  347. package/src/shade/renderer/texture/atlas/tile_atlas_slot_shift.js +22 -0
  348. package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
  349. package/src/shade/renderer/water/GPUWaterRenderer.js +4 -0
  350. package/src/shade/renderer/wind/GPUSceneWind.d.ts +52 -5
  351. package/src/shade/renderer/wind/GPUSceneWind.d.ts.map +1 -1
  352. package/src/shade/renderer/wind/GPUSceneWind.js +164 -8
  353. package/src/shade/renderer/wind/WIND_FIELD_UNIFORM.d.ts +3 -1
  354. package/src/shade/renderer/wind/WIND_FIELD_UNIFORM.d.ts.map +1 -1
  355. package/src/shade/renderer/wind/WIND_FIELD_UNIFORM.js +3 -1
  356. package/src/shade/renderer/wind/chunk_wind_field_sample_cascades.d.ts +2 -1
  357. package/src/shade/renderer/wind/chunk_wind_field_sample_cascades.d.ts.map +1 -1
  358. package/src/shade/renderer/wind/chunk_wind_field_sample_cascades.js +18 -13
  359. package/src/shade/renderer/wind/chunk_wind_field_sample_previous.d.ts +13 -0
  360. package/src/shade/renderer/wind/chunk_wind_field_sample_previous.d.ts.map +1 -0
  361. package/src/shade/renderer/wind/chunk_wind_field_sample_previous.js +23 -0
  362. package/src/shade/renderer/wind/chunk_wind_field_sample_uniform.d.ts +1 -0
  363. package/src/shade/renderer/wind/chunk_wind_field_sample_uniform.d.ts.map +1 -1
  364. package/src/shade/renderer/wind/chunk_wind_field_sample_uniform.js +6 -1
  365. package/src/shade/renderer/wind/wind_field_add_resources.d.ts +11 -0
  366. package/src/shade/renderer/wind/wind_field_add_resources.d.ts.map +1 -1
  367. package/src/shade/renderer/wind/wind_field_add_resources.js +15 -0
  368. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +1 -1
  369. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  370. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +2 -0
@@ -262,6 +262,66 @@ function bytes_equal_lengths(a, a_length, b, b_length) {
262
262
  return a_length === b_length && bytes_equal(a, b, a_length);
263
263
  }
264
264
 
265
+ /**
266
+ * One entity's newest authoritative state, waiting for the next step to be compared with what the
267
+ * client predicted. Kept per network id and written over by each state that arrives: its arrays are
268
+ * reused, so taking a state in allocates nothing once they have grown to the entity's components.
269
+ */
270
+ class PendingAuthState {
271
+ /**
272
+ * The host's frame the state is of; -1 while none is waiting.
273
+ * @type {number}
274
+ */
275
+ frame = -1;
276
+
277
+ /**
278
+ * Per replicated component, in the session's replication order: how many bytes of
279
+ * {@link bytes} are its state, -1 where the entity lacks the component.
280
+ * @type {number[]}
281
+ */
282
+ lengths = [];
283
+
284
+ /**
285
+ * Per replicated component: its wire bytes, the first `lengths[i]` of the array. An array is at
286
+ * least as long as the state it holds and usually longer; null until the component first arrives.
287
+ * @type {Array<Uint8Array|null>}
288
+ */
289
+ bytes = [];
290
+
291
+ /**
292
+ * @param {number} component_count how many components the session replicates
293
+ */
294
+ constructor(component_count) {
295
+ for (let i = 0; i < component_count; i++) {
296
+ this.lengths.push(-1);
297
+ this.bytes.push(null);
298
+ }
299
+ }
300
+
301
+ /**
302
+ * Take `length` bytes of `source`, from `offset`, as component `index`'s state.
303
+ *
304
+ * @param {number} index
305
+ * @param {Uint8Array} source
306
+ * @param {number} offset
307
+ * @param {number} length
308
+ */
309
+ write(index, source, offset, length) {
310
+ let target = this.bytes[index];
311
+
312
+ if (target === null || target.length < length) {
313
+ target = new Uint8Array(Math.max(length, 32));
314
+ this.bytes[index] = target;
315
+ }
316
+
317
+ for (let i = 0; i < length; i++) {
318
+ target[i] = source[offset + i];
319
+ }
320
+
321
+ this.lengths[index] = length;
322
+ }
323
+ }
324
+
265
325
  /**
266
326
  * High-level networking facade. Wraps the orchestrator + state machinery
267
327
  * into one config + lifecycle surface. The lower-level orchestrators
@@ -333,6 +393,53 @@ export class NetworkSession {
333
393
  */
334
394
  #replicated = new Map();
335
395
 
396
+ /**
397
+ * {@link #replicated}'s classes, in its order, set at `start()`. What runs per entity per tick
398
+ * walks this by index, with {@link #replicated_descs}: walking the Map's entries builds a
399
+ * `[key, value]` array for each one.
400
+ * @private @type {Function[]}
401
+ */
402
+ #replicated_classes = [];
403
+
404
+ /**
405
+ * {@link #replicated}'s descriptors, in its order: `#replicated_descs[i]` is
406
+ * `#replicated_classes[i]`'s.
407
+ * @private @type {Array<{interp_type_id: number, interpoland: Interpoland|null, interpolator: BinaryInterpolationAdapter|null, correction: Correction|null}>}
408
+ */
409
+ #replicated_descs = [];
410
+
411
+ /**
412
+ * Host: the entity whose state {@link #write_auth_state} writes.
413
+ * @private @type {number}
414
+ */
415
+ #auth_state_entity = -1;
416
+
417
+ /**
418
+ * Host: writes every replicated component {@link #auth_state_entity} carries, in
419
+ * `#replicated` order. One writer for the session, not one per send.
420
+ * @private @type {function(BinaryBuffer): void}
421
+ */
422
+ #write_auth_state = (buffer) => {
423
+ // read once: an adapter that sends an AUTH_STATE of its own would change it under the walk
424
+ const entity_id = this.#auth_state_entity;
425
+
426
+ const classes = this.#replicated_classes;
427
+ const world = this.world;
428
+ const registry = this.binary_registry;
429
+
430
+ for (let i = 0; i < classes.length; i++) {
431
+ const ComponentClass = classes[i];
432
+
433
+ const live = world.getComponent(entity_id, ComponentClass);
434
+
435
+ if (live === undefined) {
436
+ continue;
437
+ }
438
+
439
+ registry.getAdapter(ComponentClass.typeName).serialize(buffer, live);
440
+ }
441
+ };
442
+
336
443
  /**
337
444
  * Type_id → ComponentClass for the synthetic ReplaceComponentAction.
338
445
  * @private @type {Function[]}
@@ -478,12 +585,37 @@ export class NetworkSession {
478
585
  #prediction_history = new PredictionHistory(128);
479
586
 
480
587
  /**
481
- * Authoritative states waiting for the next step, newest per network id: the frame and each
482
- * replicated component's bytes, in `#replicated` order (`null` where the entity lacks it).
483
- * @private @type {Map<number, {frame: number, parts: Array<{type_id: number, bytes: Uint8Array}|null>}>}
588
+ * Per network id that has been sent an authoritative state: the newest one, waiting for the
589
+ * next step while its `frame` is not -1. An entry is kept once made and written over by the
590
+ * next state for its id; what is waiting is {@link #pending_auth_queue}.
591
+ * @private @type {Map<number, PendingAuthState>}
484
592
  */
485
593
  #pending_auth = new Map();
486
594
 
595
+ /**
596
+ * The authoritative states waiting for the next step, in the order their ids first arrived:
597
+ * the first {@link #pending_auth_count} entries. Parallel to {@link #pending_auth_ids}.
598
+ * @private @type {PendingAuthState[]}
599
+ */
600
+ #pending_auth_queue = [];
601
+
602
+ /**
603
+ * The network id of each state in {@link #pending_auth_queue}.
604
+ * @private @type {number[]}
605
+ */
606
+ #pending_auth_ids = [];
607
+
608
+ /** @private @type {number} */
609
+ #pending_auth_count = 0;
610
+
611
+ /**
612
+ * What an arriving authoritative state is split into. Once the whole state has been read, its
613
+ * arrays change places with those of the entry for its network id, so a state that fails to
614
+ * decode part-way leaves the one waiting before it as it was.
615
+ * @private @type {PendingAuthState|null}
616
+ */
617
+ #pending_auth_scratch = null;
618
+
487
619
  /**
488
620
  * The newest frame reconciled per network id. An authoritative state for that frame or an
489
621
  * earlier one arriving afterwards — reordered, or retransmitted — is stale: the present was
@@ -573,12 +705,60 @@ export class NetworkSession {
573
705
  #initial_sync_given = new Set();
574
706
 
575
707
  /**
576
- * Sampled-action ledger for predict-reconcile replay. The sampler
577
- * reads live input, so re-calling it during reconcile would give
578
- * wrong results; replay reads from here instead.
579
- * @private @type {Map<number, Array<{type_id: number, bytes: Uint8Array}>>}
708
+ * Client: the actions the sampler returned for the frame being predicted, from the sampler's
709
+ * return until {@link #record_and_predict} has gone through them.
710
+ * @private @type {Iterable<SimAction>|null}
711
+ */
712
+ #sampled_actions = null;
713
+
714
+ /**
715
+ * Client: the input writer of a predicted frame. Each sampled action of a registered class is
716
+ * written to the frame's slot of the client's input ring — `uint8 type_id, uint32 length`, then
717
+ * its `length` serialized bytes — and executed as those bytes say, as the host will apply it,
718
+ * rounding included: executed as sampled, a field the wire rounds (a Float32 speed) would
719
+ * predict a little differently from the host every frame.
720
+ *
721
+ * The input ring is the sampled-action ledger: the sampler reads live input, so a replay cannot
722
+ * call it again, and reads the frame's actions back from here ({@link #replay_recorded}). The
723
+ * ring holds as many frames as a replay can reach, and is cleared with the timeline.
724
+ *
725
+ * If an action throws, the frame's input is not committed and reads as empty: a replay of the
726
+ * frame executes none of its actions.
727
+ * @private @type {function(BinaryBuffer): void}
580
728
  */
581
- #sampled_actions_per_frame = new Map();
729
+ #record_and_predict = (buffer) => {
730
+ const registry = this.#peer.action_registry;
731
+
732
+ for (const action of this.#sampled_actions) {
733
+ if (!action || action.isSimAction !== true) continue;
734
+
735
+ const type_id = action.constructor.type_id;
736
+
737
+ if (registry.klass_for(type_id) === undefined) {
738
+ // not a registered action: executed as it is, for the executor to say so, and not
739
+ // recorded, since no replay could decode it
740
+ this.#client.executor.execute(action, this.local_peer_id);
741
+ continue;
742
+ }
743
+
744
+ buffer.writeUint8(type_id);
745
+
746
+ // 4 bytes reserved for the length, patched once the action is written
747
+ const length_position = buffer.position;
748
+ buffer.writeUint32(0);
749
+
750
+ const start = buffer.position;
751
+ action.serialize(buffer);
752
+ const end = buffer.position;
753
+
754
+ buffer.position = length_position;
755
+ buffer.writeUint32(end - start);
756
+ buffer.position = end;
757
+
758
+ // raw_bytes read after the write: growing the buffer replaces it
759
+ this.#execute_recorded(type_id, buffer.raw_bytes, start, end - start);
760
+ }
761
+ };
582
762
 
583
763
  /** @private @type {boolean} */
584
764
  #started = false;
@@ -977,7 +1157,8 @@ export class NetworkSession {
977
1157
  initial_delay_frames: DEFAULT_INITIAL_RENDER_DELAY_FRAMES,
978
1158
  history_size: 60,
979
1159
  safety_multiplier: 2.0,
980
- decay_per_sample_ms: 1.0,
1160
+ // the playout catches up with a calming link no faster than the clock is steered
1161
+ decay_rate: this.#time_dilation.max_dilation,
981
1162
  });
982
1163
  this.#playout = new RenderPlayout({ tick_period_ms: this.tick_period_ms, delay: this.#adaptive_render_delay });
983
1164
 
@@ -1234,6 +1415,9 @@ export class NetworkSession {
1234
1415
  }
1235
1416
  }
1236
1417
 
1418
+ this.#replicated_classes = Array.from(this.#replicated.keys());
1419
+ this.#replicated_descs = Array.from(this.#replicated.values());
1420
+
1237
1421
  this.#interpolands = this.#build_interpolands();
1238
1422
 
1239
1423
  // Build the synthetic ReplaceComponentAction now so it's in the
@@ -1277,6 +1461,8 @@ export class NetworkSession {
1277
1461
  // Only Replay rewinds, so only Replay needs a late host record put back in its frame.
1278
1462
  this.#client = new ServerAuthoritativeClient({
1279
1463
  ...orchestrator_opts,
1464
+ // the sampled-action ledger: every frame a replay can reach, the present included
1465
+ input_ring_capacity: this.frame_capacity + 1,
1280
1466
  time_dilation: this.#time_dilation,
1281
1467
  auto_reconcile: this.#reconcile === NetworkSessionReconcile.Replay,
1282
1468
  rebase_on_arrival: this.#reconcile === NetworkSessionReconcile.Replay,
@@ -1383,6 +1569,10 @@ export class NetworkSession {
1383
1569
  });
1384
1570
  this.#peer.onTimeDilationFeedback.add((_peer_id, depth, frame_number) => {
1385
1571
  if (frame_number > this.#host_frame_seen) this.#host_frame_seen = frame_number;
1572
+ // The host sends nothing of a frame in which nothing replicated changed, and names
1573
+ // its frame every tick regardless: this is what keeps the playhead its delay behind
1574
+ // the host through a pause, so what moves next is drawn that much later and no more.
1575
+ this.#playout.advance_head(frame_number);
1386
1576
  this.#host_depth_seen = depth;
1387
1577
  this.#host_marker_seen = frame_number + depth;
1388
1578
  });
@@ -1418,7 +1608,7 @@ export class NetworkSession {
1418
1608
  if (this.#reconnect_policy.accept_state_resync) {
1419
1609
  // Tier-3: drop unconfirmed predictions and wait for
1420
1610
  // the host to deliver a fresh INITIAL_SYNC.
1421
- this.#sampled_actions_per_frame.clear();
1611
+ this.#client.input_ring.clear();
1422
1612
  this.session_token = null;
1423
1613
  this.#reconnect_state = ReconnectState.Resyncing;
1424
1614
  // Restart the elapsed-ms budget so the Resyncing
@@ -1729,7 +1919,7 @@ export class NetworkSession {
1729
1919
  }
1730
1920
  this.#attached_interpolated.clear();
1731
1921
  this.#interpolation_pending.clear();
1732
- this.#pending_auth.clear();
1922
+ this.#forget_pending_auth();
1733
1923
  this.#reconciled_frame.clear();
1734
1924
  this.#prediction_history.clear();
1735
1925
 
@@ -1744,7 +1934,6 @@ export class NetworkSession {
1744
1934
  this.#remote_entities.clear();
1745
1935
  this.#owned_by.clear();
1746
1936
  this.#owner_of.clear();
1747
- this.#sampled_actions_per_frame.clear();
1748
1937
  this.#peer_inbound_mark.clear();
1749
1938
  for (const transport of this.#inbound.values()) {
1750
1939
  transport.release();
@@ -1804,7 +1993,7 @@ export class NetworkSession {
1804
1993
 
1805
1994
  this.#apply_pending_interpolation();
1806
1995
 
1807
- if (this.#client !== null && this.#pending_auth.size > 0) {
1996
+ if (this.#client !== null && this.#pending_auth_count > 0) {
1808
1997
  this.#apply_pending_corrections();
1809
1998
  }
1810
1999
 
@@ -1853,7 +2042,12 @@ export class NetworkSession {
1853
2042
  * transports of peers no longer connected.
1854
2043
  */
1855
2044
  #flush_inbound() {
1856
- for (const [peer_id, transport] of this.#inbound) {
2045
+ const inbound = this.#inbound;
2046
+
2047
+ // keys, then a lookup: the Map's entries would each be a [key, value] array, every step
2048
+ for (const peer_id of inbound.keys()) {
2049
+ const transport = inbound.get(peer_id);
2050
+
1857
2051
  if (!this.#peer.is_connected(peer_id)) {
1858
2052
  transport.release();
1859
2053
  this.#inbound.delete(peer_id);
@@ -2473,6 +2667,10 @@ export class NetworkSession {
2473
2667
  this.#inbound_release_peer = -1;
2474
2668
  if (!this.#peer.is_connected(peer_id)) return;
2475
2669
  this.#peer.release_inbound(peer_id);
2670
+ // What was held was applied in one go, and none of it was late: the wait was this
2671
+ // binding's own. The playout starts here, as a new stream's, from where the host is.
2672
+ this.#playout.reset();
2673
+ this.#playout.advance_head(this.#host_frame_seen);
2476
2674
  if (this.#inbound_release_syncs) {
2477
2675
  this.#inbound_release_syncs = false;
2478
2676
  this.onSynced.send0();
@@ -2507,9 +2705,9 @@ export class NetworkSession {
2507
2705
  */
2508
2706
  #forget_predicted_world() {
2509
2707
  this.#prediction_history.clear();
2510
- this.#pending_auth.clear();
2708
+ this.#forget_pending_auth();
2511
2709
  this.#reconciled_frame.clear();
2512
- this.#sampled_actions_per_frame.clear();
2710
+ // the sampled input goes with the timeline
2513
2711
  this.#client.forget_timeline();
2514
2712
  }
2515
2713
 
@@ -2743,24 +2941,9 @@ export class NetworkSession {
2743
2941
  return;
2744
2942
  }
2745
2943
 
2746
- this.#peer.send_auth_state(peer_id, sim_frame, network_id, (buf) => {
2747
-
2748
- // Concatenate all replicated components in #replicated order.
2749
- for (const [ComponentClass, desc] of this.#replicated) {
2750
-
2751
- const live = this.world.getComponent(entity_id, ComponentClass);
2944
+ this.#auth_state_entity = entity_id;
2752
2945
 
2753
- if (live === undefined) {
2754
- continue;
2755
- }
2756
-
2757
- const adapter = this.binary_registry.getAdapter(ComponentClass.typeName);
2758
-
2759
- adapter.serialize(buf, live);
2760
-
2761
- }
2762
-
2763
- });
2946
+ this.#peer.send_auth_state(peer_id, sim_frame, network_id, this.#write_auth_state);
2764
2947
  }
2765
2948
 
2766
2949
  // ----------------------------------------------------------------
@@ -3288,7 +3471,8 @@ export class NetworkSession {
3288
3471
  * entity carries, in `#replicated` order.
3289
3472
  */
3290
3473
  #queue_auth_state(server_frame, network_id, buffer) {
3291
- const pending = this.#pending_auth.get(network_id);
3474
+ let pending = this.#pending_auth.get(network_id);
3475
+ // a newer frame than the one waiting, or none is: -1 is below every frame
3292
3476
  if (pending !== undefined && pending.frame >= server_frame) return;
3293
3477
 
3294
3478
  const reconciled = this.#reconciled_frame.get(network_id);
@@ -3297,18 +3481,65 @@ export class NetworkSession {
3297
3481
  const entity_id = this.#peer.slot_table.entity_for(network_id);
3298
3482
  if (entity_id < 0) return;
3299
3483
 
3300
- const parts = [];
3301
- for (const [ComponentClass, desc] of this.#replicated) {
3484
+ const classes = this.#replicated_classes;
3485
+
3486
+ let scratch = this.#pending_auth_scratch;
3487
+
3488
+ if (scratch === null) {
3489
+ scratch = new PendingAuthState(classes.length);
3490
+ this.#pending_auth_scratch = scratch;
3491
+ }
3492
+
3493
+ for (let i = 0; i < classes.length; i++) {
3494
+ const ComponentClass = classes[i];
3495
+
3302
3496
  if (this.world.getComponent(entity_id, ComponentClass) === undefined) {
3303
- parts.push(null);
3497
+ scratch.lengths[i] = -1;
3304
3498
  continue;
3305
3499
  }
3500
+
3501
+ // decoded only to find where the component's bytes end
3306
3502
  const start = buffer.position;
3307
3503
  this.binary_registry.getAdapter(ComponentClass.typeName).deserialize(buffer, this.#scratch_of(ComponentClass, 0));
3308
- parts.push({ type_id: desc.interp_type_id, bytes: buffer.raw_bytes.slice(start, buffer.position) });
3504
+
3505
+ scratch.write(i, buffer.raw_bytes, start, buffer.position - start);
3506
+ }
3507
+
3508
+ // read whole: it is the newest state for its id
3509
+
3510
+ if (pending === undefined) {
3511
+ pending = new PendingAuthState(classes.length);
3512
+ this.#pending_auth.set(network_id, pending);
3309
3513
  }
3310
3514
 
3311
- this.#pending_auth.set(network_id, { frame: server_frame, parts });
3515
+ if (pending.frame < 0) {
3516
+ // not waiting yet: it joins the queue, behind the ids that arrived before it
3517
+ const index = this.#pending_auth_count++;
3518
+
3519
+ this.#pending_auth_queue[index] = pending;
3520
+ this.#pending_auth_ids[index] = network_id;
3521
+ }
3522
+
3523
+ pending.frame = server_frame;
3524
+
3525
+ // the entry takes what was read, and its own arrays are what the next state is read into
3526
+ const lengths = pending.lengths;
3527
+ pending.lengths = scratch.lengths;
3528
+ scratch.lengths = lengths;
3529
+
3530
+ const bytes = pending.bytes;
3531
+ pending.bytes = scratch.bytes;
3532
+ scratch.bytes = bytes;
3533
+ }
3534
+
3535
+ /**
3536
+ * Drop every authoritative state, waiting or not.
3537
+ */
3538
+ #forget_pending_auth() {
3539
+ this.#pending_auth.clear();
3540
+ this.#pending_auth_queue.length = 0;
3541
+ this.#pending_auth_ids.length = 0;
3542
+ this.#pending_auth_count = 0;
3312
3543
  }
3313
3544
 
3314
3545
  /**
@@ -3322,11 +3553,17 @@ export class NetworkSession {
3322
3553
  const owned = this.#owned_by.get(this.local_peer_id);
3323
3554
  if (owned === undefined) return;
3324
3555
 
3556
+ const classes = this.#replicated_classes;
3557
+ const descs = this.#replicated_descs;
3558
+
3325
3559
  for (const entity_id of owned) {
3326
3560
  const identity = world.getComponent(entity_id, NetworkIdentity);
3327
3561
  if (identity === undefined || identity.network_id < 0) continue;
3328
3562
 
3329
- for (const [ComponentClass, desc] of this.#replicated) {
3563
+ for (let i = 0; i < classes.length; i++) {
3564
+ const ComponentClass = classes[i];
3565
+ const desc = descs[i];
3566
+
3330
3567
  if (ComponentClass === NetworkIdentity) continue;
3331
3568
  const live = world.getComponent(entity_id, ComponentClass);
3332
3569
  if (live === undefined) continue;
@@ -3342,21 +3579,32 @@ export class NetworkSession {
3342
3579
  * Client, start of step: reconcile every queued authoritative state.
3343
3580
  */
3344
3581
  #apply_pending_corrections() {
3345
- const pending_auth = this.#pending_auth;
3582
+ const queue = this.#pending_auth_queue;
3583
+ const ids = this.#pending_auth_ids;
3584
+
3585
+ // the count is read each time round: a state that arrives while one is reconciled is
3586
+ // reconciled in this step too
3587
+ for (let i = 0; i < this.#pending_auth_count; i++) {
3588
+ const pending = queue[i];
3589
+ const network_id = ids[i];
3590
+
3591
+ const frame = pending.frame;
3592
+
3593
+ // no longer waiting, whatever comes of it
3594
+ pending.frame = -1;
3346
3595
 
3347
- for (const [network_id, pending] of pending_auth) {
3348
3596
  const entity_id = this.#peer.slot_table.entity_for(network_id);
3349
3597
  if (entity_id < 0 || this.#remote_entities.has(entity_id)) continue;
3350
- this.#reconciled_frame.set(network_id, pending.frame);
3598
+ this.#reconciled_frame.set(network_id, frame);
3351
3599
  try {
3352
- this.#reconcile_entity(entity_id, pending.frame, pending.parts);
3600
+ this.#reconcile_entity(entity_id, frame, pending);
3353
3601
  } catch (e) {
3354
3602
  // one entity's failure is its own: the others are corrected, and the step opens
3355
- console.error(`NetworkSession: reconciling entity ${entity_id} to frame ${pending.frame} failed:`, e);
3603
+ console.error(`NetworkSession: reconciling entity ${entity_id} to frame ${frame} failed:`, e);
3356
3604
  }
3357
3605
  }
3358
3606
 
3359
- pending_auth.clear();
3607
+ this.#pending_auth_count = 0;
3360
3608
  }
3361
3609
 
3362
3610
  /**
@@ -3366,21 +3614,27 @@ export class NetworkSession {
3366
3614
  *
3367
3615
  * @param {number} entity_id
3368
3616
  * @param {number} frame
3369
- * @param {Array<{type_id: number, bytes: Uint8Array}|null>} parts
3617
+ * @param {PendingAuthState} state the host's state of the entity at `frame`
3370
3618
  */
3371
- #reconcile_entity(entity_id, frame, parts) {
3619
+ #reconcile_entity(entity_id, frame, state) {
3372
3620
  const history = this.#prediction_history;
3373
3621
  const differs = this.#differs;
3374
3622
 
3375
3623
  // Compare first: every part must have a prediction to compare against.
3624
+ const classes = this.#replicated_classes;
3625
+ const descs = this.#replicated_descs;
3626
+
3376
3627
  let any = false;
3377
- let index = 0;
3378
- for (const [ComponentClass, desc] of this.#replicated) {
3379
- const i = index++;
3628
+ for (let i = 0; i < classes.length; i++) {
3629
+ const ComponentClass = classes[i];
3630
+ const desc = descs[i];
3631
+
3380
3632
  differs[i] = false;
3381
3633
 
3382
- const part = parts[i];
3383
- if (part === null || desc.correction === null) continue;
3634
+ const server_length = state.lengths[i];
3635
+ if (server_length < 0 || desc.correction === null) continue;
3636
+
3637
+ const server_bytes = state.bytes[i];
3384
3638
 
3385
3639
  const type_id = desc.interp_type_id;
3386
3640
  const predicted_length = history.length(entity_id, frame, type_id);
@@ -3390,11 +3644,11 @@ export class NetworkSession {
3390
3644
  }
3391
3645
 
3392
3646
  const predicted_bytes = history.bytes(entity_id, frame, type_id);
3393
- if (bytes_equal_lengths(part.bytes, part.bytes.length, predicted_bytes, predicted_length)) continue;
3647
+ if (bytes_equal_lengths(server_bytes, server_length, predicted_bytes, predicted_length)) continue;
3394
3648
 
3395
3649
  const server = this.#scratch_of(ComponentClass, 0);
3396
3650
  const predicted = this.#scratch_of(ComponentClass, 1);
3397
- this.#decode_into(ComponentClass, part.bytes, part.bytes.length, server);
3651
+ this.#decode_into(ComponentClass, server_bytes, server_length, server);
3398
3652
  this.#decode_into(ComponentClass, predicted_bytes, predicted_length, predicted);
3399
3653
 
3400
3654
  if (!desc.correction.same(server, predicted)) {
@@ -3405,15 +3659,16 @@ export class NetworkSession {
3405
3659
 
3406
3660
  if (!any) return;
3407
3661
 
3408
- index = 0;
3409
- for (const [ComponentClass, desc] of this.#replicated) {
3410
- const i = index++;
3662
+ for (let i = 0; i < classes.length; i++) {
3411
3663
  if (!differs[i]) continue;
3412
3664
 
3665
+ const ComponentClass = classes[i];
3666
+ const desc = descs[i];
3667
+
3413
3668
  const live = this.world.getComponent(entity_id, ComponentClass);
3414
3669
  if (live === undefined) continue;
3415
3670
 
3416
- const magnitude = this.#correct_component(entity_id, live, ComponentClass, desc, frame, parts[i].bytes);
3671
+ const magnitude = this.#correct_component(entity_id, live, ComponentClass, desc, frame, state.bytes[i], state.lengths[i]);
3417
3672
  this.onCorrection.send4(entity_id, frame, ComponentClass, magnitude);
3418
3673
  }
3419
3674
 
@@ -3424,9 +3679,16 @@ export class NetworkSession {
3424
3679
  * Carry the difference between the host's state and the prediction at `frame` into the live
3425
3680
  * component and into every prediction since, through the component's correction.
3426
3681
  *
3682
+ * @param {number} entity_id
3683
+ * @param {object} live the entity's live component
3684
+ * @param {Function} ComponentClass
3685
+ * @param {{interp_type_id: number, correction: Correction}} desc
3686
+ * @param {number} frame
3687
+ * @param {Uint8Array} server_bytes the host's state of the component at `frame`
3688
+ * @param {number} server_length how many of `server_bytes` are that state
3427
3689
  * @returns {number} the correction's size, as the strategy measures it
3428
3690
  */
3429
- #correct_component(entity_id, live, ComponentClass, desc, frame, server_bytes) {
3691
+ #correct_component(entity_id, live, ComponentClass, desc, frame, server_bytes, server_length) {
3430
3692
  const history = this.#prediction_history;
3431
3693
  const type_id = desc.interp_type_id;
3432
3694
  const correction = desc.correction;
@@ -3434,7 +3696,7 @@ export class NetworkSession {
3434
3696
 
3435
3697
  const server = this.#scratch_of(ComponentClass, 0);
3436
3698
  const predicted = this.#scratch_of(ComponentClass, 1);
3437
- this.#decode_into(ComponentClass, server_bytes, server_bytes.length, server);
3699
+ this.#decode_into(ComponentClass, server_bytes, server_length, server);
3438
3700
  this.#decode_into(ComponentClass, history.bytes(entity_id, frame, type_id), history.length(entity_id, frame, type_id), predicted);
3439
3701
 
3440
3702
  // the present
@@ -3455,7 +3717,7 @@ export class NetworkSession {
3455
3717
  adapter.announce(this.world, entity_id);
3456
3718
 
3457
3719
  // the predictions: the host's at `frame`, and the difference carried into each since
3458
- history.record(entity_id, frame, type_id, server_bytes, server_bytes.length);
3720
+ history.record(entity_id, frame, type_id, server_bytes, server_length);
3459
3721
 
3460
3722
  const state = this.#scratch_of(ComponentClass, 2);
3461
3723
  const buffer = this.#scratch_send_buf;
@@ -3478,40 +3740,26 @@ export class NetworkSession {
3478
3740
  // before_execute normalize hook misses it. Catch it here.
3479
3741
  this.#client.onBeforeReconcile.add(() => this.normalize_if_dirty());
3480
3742
 
3481
- // Predict: run the sampler, record each action's bytes so the replay path can re-execute
3482
- // without re-sampling, and execute the action as those bytes say — as the host will apply
3483
- // it, rounding included. Executed as sampled, a field the wire rounds (a Float32 speed)
3484
- // would predict a little differently from the host every frame.
3485
- this.#client.onPredict.add((frame, _input_writer) => {
3743
+ // Predict: run the sampler, and record and execute what it returns as the frame's input.
3744
+ this.#client.onPredict.add((frame, input_writer) => {
3486
3745
  if (this.#input_sampler === null) return;
3487
3746
  const actions = this.#input_sampler(frame);
3488
3747
  if (!actions) return;
3489
- const recorded = [];
3490
- for (const action of actions) {
3491
- if (!action || action.isSimAction !== true) continue;
3492
- const type_id = action.constructor.type_id;
3493
- const scratch = this.#scratch_send_buf;
3494
- scratch.position = 0;
3495
- action.serialize(scratch);
3496
- const bytes = scratch.raw_bytes.slice(0, scratch.position);
3497
- recorded.push({ type_id, bytes });
3498
- if (!this.#execute_recorded(type_id, bytes)) {
3499
- // not a registered action: executed as it is, for the executor to say so
3500
- this.#client.executor.execute(action, this.local_peer_id);
3501
- }
3748
+
3749
+ this.#sampled_actions = actions;
3750
+ try {
3751
+ input_writer(this.#record_and_predict);
3752
+ } finally {
3753
+ this.#sampled_actions = null;
3502
3754
  }
3503
- this.#sampled_actions_per_frame.set(frame, recorded);
3504
- this.#trim_sampled_action_ledger();
3505
3755
  });
3506
3756
 
3507
- // Replay: re-execute recorded actions from the ledger. Sampler is
3757
+ // Replay: re-execute the frame's recorded actions. Sampler is
3508
3758
  // NOT called again — live input has moved on.
3509
- this.#client.onReplay.add((frame, _input_reader) => {
3510
- const recorded = this.#sampled_actions_per_frame.get(frame);
3511
- if (!recorded) return;
3512
- for (const { type_id, bytes } of recorded) {
3513
- this.#execute_recorded(type_id, bytes);
3514
- }
3759
+ this.#client.onReplay.add((frame, input_reader) => {
3760
+ if (input_reader === null) return;
3761
+
3762
+ this.#replay_recorded(input_reader, this.#client.input_ring.write_end_for(frame));
3515
3763
  });
3516
3764
 
3517
3765
  // Apply auth state: deserialize concatenated replicated-component
@@ -3519,7 +3767,11 @@ export class NetworkSession {
3519
3767
  this.#client.onApplyAuthState.add((_server_frame, network_id, buffer) => {
3520
3768
  const local = this.#client.slot_table.entity_for(network_id);
3521
3769
  if (local < 0) return;
3522
- for (const [ComponentClass] of this.#replicated) {
3770
+ const classes = this.#replicated_classes;
3771
+
3772
+ for (let i = 0; i < classes.length; i++) {
3773
+ const ComponentClass = classes[i];
3774
+
3523
3775
  const live = this.world.getComponent(local, ComponentClass);
3524
3776
  if (live === undefined) continue;
3525
3777
  const adapter = this.binary_registry.getAdapter(ComponentClass.typeName);
@@ -3530,36 +3782,46 @@ export class NetworkSession {
3530
3782
  }
3531
3783
 
3532
3784
  /**
3533
- * Execute the action `bytes` encode, as this client's own.
3534
- * @param {number} type_id
3785
+ * Execute every action recorded in the first `end` bytes of `input`, a frame's slot of the
3786
+ * client's input ring as {@link #record_and_predict} wrote it, in the order they were recorded.
3787
+ *
3788
+ * @param {BinaryBuffer} input positioned at the frame's first record
3789
+ * @param {number} end how many bytes the frame holds
3790
+ */
3791
+ #replay_recorded(input, end) {
3792
+ while (input.position < end) {
3793
+ const type_id = input.readUint8();
3794
+ const length = input.readUint32();
3795
+ const start = input.position;
3796
+
3797
+ this.#execute_recorded(type_id, input.raw_bytes, start, length);
3798
+
3799
+ input.position = start + length;
3800
+ }
3801
+ }
3802
+
3803
+ /**
3804
+ * Execute the action that `length` bytes of `bytes`, from `offset`, encode, as this client's
3805
+ * own. The action is decoded from a copy, so a decoder cannot write over what was recorded.
3806
+ *
3807
+ * @param {number} type_id a registered action's
3535
3808
  * @param {Uint8Array} bytes
3536
- * @returns {boolean} false when no action is registered under `type_id`
3809
+ * @param {number} offset
3810
+ * @param {number} length
3537
3811
  */
3538
- #execute_recorded(type_id, bytes) {
3539
- const klass = this.#peer.action_registry.klass_for(type_id);
3540
- if (klass === undefined) return false;
3812
+ #execute_recorded(type_id, bytes, offset, length) {
3813
+ const registry = this.#peer.action_registry;
3541
3814
 
3542
- const action = this.#peer.action_registry.acquire(klass);
3815
+ const action = registry.acquire(registry.klass_for(type_id));
3543
3816
  try {
3544
3817
  const scratch = this.#scratch_interp_buf;
3545
3818
  scratch.position = 0;
3546
- scratch.writeBytes(bytes, 0, bytes.length);
3819
+ scratch.writeBytes(bytes, offset, length);
3547
3820
  scratch.position = 0;
3548
3821
  action.deserialize(scratch);
3549
3822
  this.#client.executor.execute(action, this.local_peer_id);
3550
3823
  } finally {
3551
- this.#peer.action_registry.release(action);
3552
- }
3553
-
3554
- return true;
3555
- }
3556
-
3557
- #trim_sampled_action_ledger() {
3558
- const action_log = this.#peer.action_log;
3559
- if (action_log === undefined) return;
3560
- const oldest_keep = Math.max(0, this.#local_frame - action_log.frame_capacity);
3561
- for (const f of this.#sampled_actions_per_frame.keys()) {
3562
- if (f < oldest_keep) this.#sampled_actions_per_frame.delete(f);
3824
+ registry.release(action);
3563
3825
  }
3564
3826
  }
3565
3827