@woosh/meep-engine 3.64.1 → 3.67.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 (372) 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/graphics3/GrassSurfaceSystem.d.ts +153 -0
  29. package/src/engine/graphics3/GrassSurfaceSystem.d.ts.map +1 -0
  30. package/src/engine/graphics3/GrassSurfaceSystem.js +1076 -0
  31. package/src/engine/graphics3/GroundCoverSystem.d.ts +33 -0
  32. package/src/engine/graphics3/GroundCoverSystem.d.ts.map +1 -0
  33. package/src/engine/graphics3/GroundCoverSystem.js +58 -0
  34. package/src/engine/network/NetworkSession.d.ts.map +1 -1
  35. package/src/engine/network/NetworkSession.js +372 -110
  36. package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
  37. package/src/engine/network/orchestrator/NetworkPeer.js +6 -1
  38. package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts.map +1 -1
  39. package/src/engine/network/orchestrator/ServerAuthoritativeClient.js +9 -2
  40. package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts.map +1 -1
  41. package/src/engine/network/orchestrator/ServerAuthoritativeServer.js +325 -140
  42. package/src/engine/network/sim/SimActionExecutor.d.ts +4 -1
  43. package/src/engine/network/sim/SimActionExecutor.d.ts.map +1 -1
  44. package/src/engine/network/sim/SimActionExecutor.js +65 -9
  45. package/src/engine/network/state/PredictionHistory.d.ts.map +1 -1
  46. package/src/engine/network/state/PredictionHistory.js +6 -1
  47. package/src/engine/network/time/AdaptiveRenderDelay.d.ts +25 -14
  48. package/src/engine/network/time/AdaptiveRenderDelay.d.ts.map +1 -1
  49. package/src/engine/network/time/AdaptiveRenderDelay.js +38 -20
  50. package/src/engine/network/time/RenderPlayout.d.ts +23 -3
  51. package/src/engine/network/time/RenderPlayout.d.ts.map +1 -1
  52. package/src/engine/network/time/RenderPlayout.js +40 -4
  53. package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
  54. package/src/engine/physics/fluid/obstacle/chunk_fluid_obstacle_record.d.ts +5 -1
  55. package/src/engine/physics/fluid/obstacle/chunk_fluid_obstacle_record.d.ts.map +1 -1
  56. package/src/engine/physics/fluid/obstacle/chunk_fluid_obstacle_record.js +27 -1
  57. package/src/format/lut/cube/CubeLut.d.ts +38 -0
  58. package/src/format/lut/cube/CubeLut.d.ts.map +1 -0
  59. package/src/format/lut/cube/CubeLut.js +23 -0
  60. package/src/format/lut/cube/cube_read.d.ts +23 -0
  61. package/src/format/lut/cube/cube_read.d.ts.map +1 -0
  62. package/src/format/lut/cube/cube_read.js +199 -0
  63. package/src/format/lut/cube/cube_write.d.ts +15 -0
  64. package/src/format/lut/cube/cube_write.d.ts.map +1 -0
  65. package/src/format/lut/cube/cube_write.js +90 -0
  66. package/src/shade/device/shader/ShaderModuleCompiler.d.ts +2 -0
  67. package/src/shade/device/shader/ShaderModuleCompiler.d.ts.map +1 -1
  68. package/src/shade/device/shader/ShaderModuleCompiler.js +25 -2
  69. package/src/shade/playground/grass_surfaces/index.html +75 -0
  70. package/src/shade/playground/grass_surfaces/main.d.ts +2 -0
  71. package/src/shade/playground/grass_surfaces/main.d.ts.map +1 -0
  72. package/src/shade/playground/grass_surfaces/main.js +593 -0
  73. package/src/shade/playground/grass_surfaces/read_grass_surfaces.d.ts +62 -0
  74. package/src/shade/playground/grass_surfaces/read_grass_surfaces.d.ts.map +1 -0
  75. package/src/shade/playground/grass_surfaces/read_grass_surfaces.js +188 -0
  76. package/src/shade/playground/probe_clipmap/README.md +1 -0
  77. package/src/shade/playground/probe_clipmap/index.html +5 -0
  78. package/src/shade/playground/probe_clipmap/main.d.ts.map +1 -1
  79. package/src/shade/playground/probe_clipmap/main.js +7 -0
  80. package/src/shade/playground/probe_clipmap_box/README.md +5 -1
  81. package/src/shade/playground/probe_clipmap_box/index.html +12 -0
  82. package/src/shade/playground/probe_clipmap_box/main.d.ts.map +1 -1
  83. package/src/shade/playground/probe_clipmap_box/main.js +15 -0
  84. package/src/shade/playground/probe_clipmap_box/scene.d.ts +8 -1
  85. package/src/shade/playground/probe_clipmap_box/scene.d.ts.map +1 -1
  86. package/src/shade/playground/probe_clipmap_box/scene.js +74 -6
  87. package/src/shade/renderer/Renderer.d.ts.map +1 -1
  88. package/src/shade/renderer/Renderer.js +59 -55
  89. package/src/shade/renderer/deferred/tonemap/ColorGrade.d.ts +73 -4
  90. package/src/shade/renderer/deferred/tonemap/ColorGrade.d.ts.map +1 -1
  91. package/src/shade/renderer/deferred/tonemap/ColorGrade.js +113 -7
  92. package/src/shade/renderer/deferred/tonemap/TONEMAP_PURKINJE_SHIFT.d.ts +12 -0
  93. package/src/shade/renderer/deferred/tonemap/TONEMAP_PURKINJE_SHIFT.d.ts.map +1 -0
  94. package/src/shade/renderer/deferred/tonemap/TONEMAP_PURKINJE_SHIFT.js +12 -0
  95. package/src/shade/renderer/deferred/tonemap/ToneMapper.d.ts +15 -1
  96. package/src/shade/renderer/deferred/tonemap/ToneMapper.d.ts.map +1 -1
  97. package/src/shade/renderer/deferred/tonemap/ToneMapper.js +31 -3
  98. package/src/shade/renderer/deferred/tonemap/chunk_tonemap_purkinje.d.ts +25 -0
  99. package/src/shade/renderer/deferred/tonemap/chunk_tonemap_purkinje.d.ts.map +1 -0
  100. package/src/shade/renderer/deferred/tonemap/chunk_tonemap_purkinje.js +51 -0
  101. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_lut.d.ts +2 -2
  102. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_lut.d.ts.map +1 -1
  103. package/src/shade/renderer/deferred/tonemap/shader_tonemap_HDR_lut.js +6 -3
  104. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_lut.d.ts +3 -2
  105. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_lut.d.ts.map +1 -1
  106. package/src/shade/renderer/deferred/tonemap/shader_tonemap_LDR_lut.js +7 -3
  107. package/src/shade/renderer/extension/ViewTextures.d.ts +12 -5
  108. package/src/shade/renderer/extension/ViewTextures.d.ts.map +1 -1
  109. package/src/shade/renderer/extension/ViewTextures.js +19 -5
  110. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +3 -1
  111. package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts.map +1 -1
  112. package/src/shade/renderer/fluid/GPUFluidCascadeStack.js +6 -1
  113. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +7 -0
  114. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts.map +1 -1
  115. package/src/shade/renderer/fluid/forcing/GPUFluidForcing.js +10 -0
  116. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +7 -1
  117. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts.map +1 -1
  118. package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +46 -15
  119. package/src/shade/renderer/geometry/sdf/bundle/ModelCacheBundle.d.ts +3 -2
  120. package/src/shade/renderer/geometry/sdf/bundle/ModelCacheBundle.d.ts.map +1 -1
  121. package/src/shade/renderer/geometry/sdf/bundle/ModelCacheBundle.js +3 -2
  122. package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_sort_morton.d.ts +22 -0
  123. package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_sort_morton.d.ts.map +1 -0
  124. package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_sort_morton.js +247 -0
  125. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts +50 -0
  126. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
  127. package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +101 -0
  128. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts +2 -1
  129. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts.map +1 -1
  130. package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.js +2 -1
  131. package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.d.ts +8 -0
  132. package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.d.ts.map +1 -1
  133. package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.js +12 -0
  134. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.d.ts +12 -6
  135. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.d.ts.map +1 -1
  136. package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.js +35 -29
  137. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_clipmap.d.ts.map +1 -1
  138. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_clipmap.js +4 -2
  139. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_material.d.ts.map +1 -1
  140. package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_material.js +6 -4
  141. package/src/shade/renderer/global_illumination/probe_clipmap/material/GPUBrickMaterial.d.ts.map +1 -1
  142. package/src/shade/renderer/global_illumination/probe_clipmap/material/GPUBrickMaterial.js +2 -1
  143. package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material.d.ts +6 -5
  144. package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material.d.ts.map +1 -1
  145. package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material.js +15 -14
  146. package/src/shade/renderer/global_illumination/probe_clipmap/material/shader_brick_material_gather.d.ts.map +1 -1
  147. package/src/shade/renderer/global_illumination/probe_clipmap/material/shader_brick_material_gather.js +4 -2
  148. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +19 -2
  149. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
  150. package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +128 -10
  151. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts +19 -1
  152. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts.map +1 -1
  153. package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.js +27 -2
  154. package/src/shade/renderer/global_illumination/probe_clipmap/probe/ProbeClipmapScreenWants.d.ts +19 -11
  155. package/src/shade/renderer/global_illumination/probe_clipmap/probe/ProbeClipmapScreenWants.d.ts.map +1 -1
  156. package/src/shade/renderer/global_illumination/probe_clipmap/probe/ProbeClipmapScreenWants.js +35 -11
  157. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts.map +1 -1
  158. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.js +3 -1
  159. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_box_cages.d.ts +40 -0
  160. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_box_cages.d.ts.map +1 -0
  161. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_box_cages.js +174 -0
  162. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_material.d.ts +4 -4
  163. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_material.js +10 -10
  164. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_parallax.d.ts +31 -0
  165. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_parallax.d.ts.map +1 -0
  166. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_parallax.js +54 -0
  167. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts +8 -4
  168. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts.map +1 -1
  169. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.js +10 -21
  170. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.d.ts +7 -2
  171. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.d.ts.map +1 -1
  172. package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.js +33 -29
  173. package/src/shade/renderer/global_illumination/probe_clipmap/probe/graph_probe_clipmap_want_meshlets.d.ts +28 -0
  174. package/src/shade/renderer/global_illumination/probe_clipmap/probe/graph_probe_clipmap_want_meshlets.d.ts.map +1 -0
  175. package/src/shade/renderer/global_illumination/probe_clipmap/probe/graph_probe_clipmap_want_meshlets.js +138 -0
  176. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.d.ts +13 -9
  177. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.d.ts.map +1 -1
  178. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.js +18 -11
  179. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_light.js +1 -1
  180. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_relocate.d.ts.map +1 -1
  181. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_relocate.js +4 -2
  182. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_retire.d.ts.map +1 -1
  183. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_retire.js +2 -3
  184. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_schedule.d.ts +5 -3
  185. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_schedule.d.ts.map +1 -1
  186. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_schedule.js +15 -30
  187. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.js +1 -1
  188. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.d.ts.map +1 -1
  189. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.js +4 -2
  190. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.d.ts +11 -0
  191. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.d.ts.map +1 -1
  192. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.js +29 -2
  193. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_late.d.ts +40 -0
  194. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_late.d.ts.map +1 -0
  195. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_late.js +126 -0
  196. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_meshlets.d.ts +36 -0
  197. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_meshlets.d.ts.map +1 -0
  198. package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_meshlets.js +221 -0
  199. package/src/shade/renderer/gpu_primitive/age_eviction/chunk_age_eviction.d.ts +40 -0
  200. package/src/shade/renderer/gpu_primitive/age_eviction/chunk_age_eviction.d.ts.map +1 -0
  201. package/src/shade/renderer/gpu_primitive/age_eviction/chunk_age_eviction.js +86 -0
  202. package/src/shade/renderer/grass/blade/GPUGrassBlades.d.ts +135 -0
  203. package/src/shade/renderer/grass/blade/GPUGrassBlades.d.ts.map +1 -0
  204. package/src/shade/renderer/grass/blade/GPUGrassBlades.js +676 -0
  205. package/src/shade/renderer/grass/blade/GRASS_BLADE.d.ts +145 -0
  206. package/src/shade/renderer/grass/blade/GRASS_BLADE.d.ts.map +1 -0
  207. package/src/shade/renderer/grass/blade/GRASS_BLADE.js +179 -0
  208. package/src/shade/renderer/grass/blade/chunk_grass_blade.d.ts +63 -0
  209. package/src/shade/renderer/grass/blade/chunk_grass_blade.d.ts.map +1 -0
  210. package/src/shade/renderer/grass/blade/chunk_grass_blade.js +244 -0
  211. package/src/shade/renderer/grass/blade/chunk_grass_blade_wind.d.ts +58 -0
  212. package/src/shade/renderer/grass/blade/chunk_grass_blade_wind.d.ts.map +1 -0
  213. package/src/shade/renderer/grass/blade/chunk_grass_blade_wind.js +174 -0
  214. package/src/shade/renderer/grass/blade/grass_blade_id_draw.d.ts +25 -0
  215. package/src/shade/renderer/grass/blade/grass_blade_id_draw.d.ts.map +1 -0
  216. package/src/shade/renderer/grass/blade/grass_blade_id_draw.js +133 -0
  217. package/src/shade/renderer/grass/blade/grass_blade_mechanics.d.ts +80 -0
  218. package/src/shade/renderer/grass/blade/grass_blade_mechanics.d.ts.map +1 -0
  219. package/src/shade/renderer/grass/blade/grass_blade_mechanics.js +92 -0
  220. package/src/shade/renderer/grass/blade/grass_blade_resolve.d.ts +29 -0
  221. package/src/shade/renderer/grass/blade/grass_blade_resolve.d.ts.map +1 -0
  222. package/src/shade/renderer/grass/blade/grass_blade_resolve.js +175 -0
  223. package/src/shade/renderer/grass/blade/shader_grass_blade_draw_args.d.ts +14 -0
  224. package/src/shade/renderer/grass/blade/shader_grass_blade_draw_args.d.ts.map +1 -0
  225. package/src/shade/renderer/grass/blade/shader_grass_blade_draw_args.js +45 -0
  226. package/src/shade/renderer/grass/blade/shader_grass_blade_expand.d.ts +61 -0
  227. package/src/shade/renderer/grass/blade/shader_grass_blade_expand.d.ts.map +1 -0
  228. package/src/shade/renderer/grass/blade/shader_grass_blade_expand.js +340 -0
  229. package/src/shade/renderer/grass/blade/shader_grass_cell_count.d.ts +46 -0
  230. package/src/shade/renderer/grass/blade/shader_grass_cell_count.d.ts.map +1 -0
  231. package/src/shade/renderer/grass/blade/shader_grass_cell_count.js +280 -0
  232. package/src/shade/renderer/grass/population/chunk_grass_population.d.ts +60 -0
  233. package/src/shade/renderer/grass/population/chunk_grass_population.d.ts.map +1 -0
  234. package/src/shade/renderer/grass/population/chunk_grass_population.js +171 -0
  235. package/src/shade/renderer/grass/press/GPUGrassPress.d.ts +99 -0
  236. package/src/shade/renderer/grass/press/GPUGrassPress.d.ts.map +1 -0
  237. package/src/shade/renderer/grass/press/GPUGrassPress.js +436 -0
  238. package/src/shade/renderer/grass/press/GRASS_PRESS.d.ts +179 -0
  239. package/src/shade/renderer/grass/press/GRASS_PRESS.d.ts.map +1 -0
  240. package/src/shade/renderer/grass/press/GRASS_PRESS.js +217 -0
  241. package/src/shade/renderer/grass/press/chunk_grass_press.d.ts +65 -0
  242. package/src/shade/renderer/grass/press/chunk_grass_press.d.ts.map +1 -0
  243. package/src/shade/renderer/grass/press/chunk_grass_press.js +296 -0
  244. package/src/shade/renderer/grass/press/shader_grass_press_mark.d.ts +31 -0
  245. package/src/shade/renderer/grass/press/shader_grass_press_mark.d.ts.map +1 -0
  246. package/src/shade/renderer/grass/press/shader_grass_press_mark.js +169 -0
  247. package/src/shade/renderer/grass/press/shader_grass_press_stamp.d.ts +27 -0
  248. package/src/shade/renderer/grass/press/shader_grass_press_stamp.d.ts.map +1 -0
  249. package/src/shade/renderer/grass/press/shader_grass_press_stamp.js +183 -0
  250. package/src/shade/renderer/grass/surface/GPUGrassSurfaces.d.ts +193 -0
  251. package/src/shade/renderer/grass/surface/GPUGrassSurfaces.d.ts.map +1 -0
  252. package/src/shade/renderer/grass/surface/GPUGrassSurfaces.js +1253 -0
  253. package/src/shade/renderer/grass/surface/GRASS_SURFACE.d.ts +211 -0
  254. package/src/shade/renderer/grass/surface/GRASS_SURFACE.d.ts.map +1 -0
  255. package/src/shade/renderer/grass/surface/GRASS_SURFACE.js +241 -0
  256. package/src/shade/renderer/grass/surface/GRASS_SURFACE_VIEW.d.ts +82 -0
  257. package/src/shade/renderer/grass/surface/GRASS_SURFACE_VIEW.d.ts.map +1 -0
  258. package/src/shade/renderer/grass/surface/GRASS_SURFACE_VIEW.js +111 -0
  259. package/src/shade/renderer/grass/surface/chunk_grass_column_cross.d.ts +39 -0
  260. package/src/shade/renderer/grass/surface/chunk_grass_column_cross.d.ts.map +1 -0
  261. package/src/shade/renderer/grass/surface/chunk_grass_column_cross.js +85 -0
  262. package/src/shade/renderer/grass/surface/chunk_grass_directory.d.ts +29 -0
  263. package/src/shade/renderer/grass/surface/chunk_grass_directory.d.ts.map +1 -0
  264. package/src/shade/renderer/grass/surface/chunk_grass_directory.js +112 -0
  265. package/src/shade/renderer/grass/surface/chunk_grass_slot.d.ts +27 -0
  266. package/src/shade/renderer/grass/surface/chunk_grass_slot.d.ts.map +1 -0
  267. package/src/shade/renderer/grass/surface/chunk_grass_slot.js +50 -0
  268. package/src/shade/renderer/grass/surface/chunk_grass_surface_frame.d.ts +21 -0
  269. package/src/shade/renderer/grass/surface/chunk_grass_surface_frame.d.ts.map +1 -0
  270. package/src/shade/renderer/grass/surface/chunk_grass_surface_frame.js +41 -0
  271. package/src/shade/renderer/grass/surface/chunk_grass_surface_window.d.ts +32 -0
  272. package/src/shade/renderer/grass/surface/chunk_grass_surface_window.d.ts.map +1 -0
  273. package/src/shade/renderer/grass/surface/chunk_grass_surface_window.js +136 -0
  274. package/src/shade/renderer/grass/surface/chunk_grass_surfel.d.ts +37 -0
  275. package/src/shade/renderer/grass/surface/chunk_grass_surfel.d.ts.map +1 -0
  276. package/src/shade/renderer/grass/surface/chunk_grass_surfel.js +85 -0
  277. package/src/shade/renderer/grass/surface/chunk_grass_tile.d.ts +25 -0
  278. package/src/shade/renderer/grass/surface/chunk_grass_tile.d.ts.map +1 -0
  279. package/src/shade/renderer/grass/surface/chunk_grass_tile.js +52 -0
  280. package/src/shade/renderer/grass/surface/shader_grass_directory_fill.d.ts +23 -0
  281. package/src/shade/renderer/grass/surface/shader_grass_directory_fill.d.ts.map +1 -0
  282. package/src/shade/renderer/grass/surface/shader_grass_directory_fill.js +87 -0
  283. package/src/shade/renderer/grass/surface/shader_grass_surface_bake.d.ts +43 -0
  284. package/src/shade/renderer/grass/surface/shader_grass_surface_bake.d.ts.map +1 -0
  285. package/src/shade/renderer/grass/surface/shader_grass_surface_bake.js +265 -0
  286. package/src/shade/renderer/grass/surface/shader_grass_surface_bake_command.d.ts +13 -0
  287. package/src/shade/renderer/grass/surface/shader_grass_surface_bake_command.d.ts.map +1 -0
  288. package/src/shade/renderer/grass/surface/shader_grass_surface_bake_command.js +49 -0
  289. package/src/shade/renderer/grass/surface/shader_grass_surface_invalidate.d.ts +62 -0
  290. package/src/shade/renderer/grass/surface/shader_grass_surface_invalidate.d.ts.map +1 -0
  291. package/src/shade/renderer/grass/surface/shader_grass_surface_invalidate.js +162 -0
  292. package/src/shade/renderer/grass/surface/shader_grass_surface_retire.d.ts +40 -0
  293. package/src/shade/renderer/grass/surface/shader_grass_surface_retire.d.ts.map +1 -0
  294. package/src/shade/renderer/grass/surface/shader_grass_surface_retire.js +155 -0
  295. package/src/shade/renderer/grass/surface/shader_grass_surface_schedule.d.ts +19 -0
  296. package/src/shade/renderer/grass/surface/shader_grass_surface_schedule.d.ts.map +1 -0
  297. package/src/shade/renderer/grass/surface/shader_grass_surface_schedule.js +58 -0
  298. package/src/shade/renderer/grass/surface/shader_grass_surface_want.d.ts +30 -0
  299. package/src/shade/renderer/grass/surface/shader_grass_surface_want.d.ts.map +1 -0
  300. package/src/shade/renderer/grass/surface/shader_grass_surface_want.js +251 -0
  301. package/src/shade/renderer/grass/surface/shader_grass_surface_window_count.d.ts +21 -0
  302. package/src/shade/renderer/grass/surface/shader_grass_surface_window_count.d.ts.map +1 -0
  303. package/src/shade/renderer/grass/surface/shader_grass_surface_window_count.js +75 -0
  304. package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.d.ts +35 -9
  305. package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.d.ts.map +1 -1
  306. package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.js +81 -11
  307. package/src/shade/renderer/postprocess/eye/shader_autoexposure_adapt.d.ts.map +1 -1
  308. package/src/shade/renderer/postprocess/eye/shader_autoexposure_adapt.js +4 -1
  309. package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.d.ts.map +1 -1
  310. package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.js +4 -23
  311. package/src/shade/renderer/postprocess/velocity/view_velocity_matrices.d.ts +12 -0
  312. package/src/shade/renderer/postprocess/velocity/view_velocity_matrices.d.ts.map +1 -0
  313. package/src/shade/renderer/postprocess/velocity/view_velocity_matrices.js +29 -0
  314. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts.map +1 -1
  315. package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +22 -0
  316. package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
  317. package/src/shade/renderer/scene/GPUSceneContext.js +3 -0
  318. package/src/shade/renderer/scene/GRASS_SURFACE_PARAMS_STRUCT.d.ts +27 -0
  319. package/src/shade/renderer/scene/GRASS_SURFACE_PARAMS_STRUCT.d.ts.map +1 -0
  320. package/src/shade/renderer/scene/GRASS_SURFACE_PARAMS_STRUCT.js +38 -0
  321. package/src/shade/renderer/scene/MESH_GROUND_COVER_STRUCT.d.ts +28 -0
  322. package/src/shade/renderer/scene/MESH_GROUND_COVER_STRUCT.d.ts.map +1 -0
  323. package/src/shade/renderer/scene/MESH_GROUND_COVER_STRUCT.js +58 -0
  324. package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.d.ts.map +1 -1
  325. package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.js +8 -0
  326. package/src/shade/renderer/shader/chunk/color/conversion/chunk_CRM_REC709_AP1.d.ts +6 -0
  327. package/src/shade/renderer/shader/chunk/color/conversion/chunk_CRM_REC709_AP1.d.ts.map +1 -1
  328. package/src/shade/renderer/shader/chunk/color/conversion/chunk_CRM_REC709_AP1.js +7 -0
  329. package/src/shade/renderer/shader/chunk/color/grade/chunk_color_grade.d.ts +4 -4
  330. package/src/shade/renderer/shader/chunk/color/grade/chunk_color_grade.d.ts.map +1 -1
  331. package/src/shade/renderer/shader/chunk/color/grade/chunk_color_grade.js +86 -5
  332. package/src/shade/renderer/shader/chunk/color/tonemap/purkinje/chunk_apply_purkinje_shift.d.ts +65 -0
  333. package/src/shade/renderer/shader/chunk/color/tonemap/purkinje/chunk_apply_purkinje_shift.d.ts.map +1 -0
  334. package/src/shade/renderer/shader/chunk/color/tonemap/purkinje/chunk_apply_purkinje_shift.js +136 -0
  335. package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_nearest_among.d.ts +37 -0
  336. package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_nearest_among.d.ts.map +1 -0
  337. package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_nearest_among.js +148 -0
  338. package/src/shade/renderer/shader/chunk/sdf/chunk_shape_record_line_span.d.ts +20 -0
  339. package/src/shade/renderer/shader/chunk/sdf/chunk_shape_record_line_span.d.ts.map +1 -0
  340. package/src/shade/renderer/shader/chunk/sdf/chunk_shape_record_line_span.js +169 -0
  341. package/src/shade/renderer/texture/atlas/chunk_tile_atlas_slot_origin.d.ts +18 -0
  342. package/src/shade/renderer/texture/atlas/chunk_tile_atlas_slot_origin.d.ts.map +1 -1
  343. package/src/shade/renderer/texture/atlas/chunk_tile_atlas_slot_origin.js +28 -0
  344. package/src/shade/renderer/texture/atlas/tile_atlas_slot_shift.d.ts +13 -0
  345. package/src/shade/renderer/texture/atlas/tile_atlas_slot_shift.d.ts.map +1 -0
  346. package/src/shade/renderer/texture/atlas/tile_atlas_slot_shift.js +22 -0
  347. package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
  348. package/src/shade/renderer/water/GPUWaterRenderer.js +4 -0
  349. package/src/shade/renderer/wind/GPUSceneWind.d.ts +52 -5
  350. package/src/shade/renderer/wind/GPUSceneWind.d.ts.map +1 -1
  351. package/src/shade/renderer/wind/GPUSceneWind.js +164 -8
  352. package/src/shade/renderer/wind/WIND_FIELD_UNIFORM.d.ts +3 -1
  353. package/src/shade/renderer/wind/WIND_FIELD_UNIFORM.d.ts.map +1 -1
  354. package/src/shade/renderer/wind/WIND_FIELD_UNIFORM.js +3 -1
  355. package/src/shade/renderer/wind/chunk_wind_field_sample_cascades.d.ts +2 -1
  356. package/src/shade/renderer/wind/chunk_wind_field_sample_cascades.d.ts.map +1 -1
  357. package/src/shade/renderer/wind/chunk_wind_field_sample_cascades.js +18 -13
  358. package/src/shade/renderer/wind/chunk_wind_field_sample_previous.d.ts +13 -0
  359. package/src/shade/renderer/wind/chunk_wind_field_sample_previous.d.ts.map +1 -0
  360. package/src/shade/renderer/wind/chunk_wind_field_sample_previous.js +23 -0
  361. package/src/shade/renderer/wind/chunk_wind_field_sample_uniform.d.ts +1 -0
  362. package/src/shade/renderer/wind/chunk_wind_field_sample_uniform.d.ts.map +1 -1
  363. package/src/shade/renderer/wind/chunk_wind_field_sample_uniform.js +6 -1
  364. package/src/shade/renderer/wind/wind_field_add_resources.d.ts +11 -0
  365. package/src/shade/renderer/wind/wind_field_add_resources.d.ts.map +1 -1
  366. package/src/shade/renderer/wind/wind_field_add_resources.js +15 -0
  367. package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +1 -1
  368. package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
  369. package/src/shade/wgsl/emulator/WGSLLanguageCore.js +2 -0
  370. package/src/shade/renderer/shader/chunk/color/tonemap/purkinjie/chunk_apply_purkinjie_shift.d.ts +0 -11
  371. package/src/shade/renderer/shader/chunk/color/tonemap/purkinjie/chunk_apply_purkinjie_shift.d.ts.map +0 -1
  372. package/src/shade/renderer/shader/chunk/color/tonemap/purkinjie/chunk_apply_purkinjie_shift.js +0 -56
@@ -1,8 +1,6 @@
1
1
  import { assert } from "../../../core/assert.js";
2
2
  import { BinaryBuffer } from "../../../core/binary/BinaryBuffer.js";
3
- import { binarySearchHighIndex } from "../../../core/collection/array/binarySearchHighIndex.js";
4
3
  import Signal from "../../../core/events/signal/Signal.js";
5
- import { number_compare_ascending } from "../../../core/primitives/numbers/number_compare_ascending.js";
6
4
  import { NetworkIdentity } from "../ecs/components/NetworkIdentity.js";
7
5
  import { make_owner_authorization } from "../ecs/owner_authorization.js";
8
6
  import { Replicator } from "../replication/Replicator.js";
@@ -104,26 +102,71 @@ export const LateInput = Object.freeze({
104
102
  * @copyright Company Named Limited (c) 2026
105
103
  */
106
104
  export class ServerAuthoritativeServer {
107
- // Per-tick pending input log. Parallel arrays (no per-action object
108
- // alloc) of newly-arrived action records, plus a sorted unique set
109
- // of the frames they reference.
105
+ // Pending input: the records that have arrived and are not applied yet. Parallel arrays, of
106
+ // which the first #pending_count entries are the records. Like every scratch list here, the
107
+ // arrays are written over from the start and never cut short: an array cut to length 0 gives
108
+ // up its storage, and the next record allocates it again.
109
+ #pending_count = 0;
110
110
  #pending_frames = /** @type {number[]} */ ([]);
111
111
  #pending_senders = /** @type {number[]} */ ([]);
112
112
  #pending_type_ids = /** @type {number[]} */ ([]);
113
+ // each from the payload pool, and at least as long as the record: see #pending_lengths
113
114
  #pending_payloads = /** @type {Uint8Array[]} */ ([]);
114
- #pending_referenced_frames = /** @type {number[]} */ ([]);
115
+ #pending_lengths = /** @type {number[]} */ ([]);
116
+
117
+ /**
118
+ * The oldest frame a pending record is tagged for: where a tick's replay starts. Infinity
119
+ * while nothing is pending.
120
+ * @type {number}
121
+ */
122
+ #pending_oldest_frame = Infinity;
123
+
115
124
  #peer_max_received_frame;
116
- // Scratch for the replay loop.
117
- #historical_scratch = /** @type {Array<{type_id:number, sender_id:number, payload:Uint8Array}>} */ ([]);
125
+
126
+ /**
127
+ * Byte arrays for record payloads, free to be taken: the first {@link #payload_pool_count}
128
+ * entries. A record is copied out of a buffer that is about to be reused — a receive buffer, a
129
+ * log frame being reopened — and its copy goes back here once the record is applied or dropped,
130
+ * so a steady stream of input allocates none.
131
+ * @type {Uint8Array[]}
132
+ */
133
+ #payload_pool = [];
134
+ #payload_pool_count = 0;
118
135
 
119
136
  /**
120
137
  * The recorded — not executed — records of the frame being replayed ({@link SENDER_RECORDED}),
121
138
  * in log order: carried into the replayed frame as they are, since what produced them is not
122
- * re-run by a replay.
123
- * @type {Array<{type_id:number, payload:Uint8Array}>}
139
+ * re-run by a replay. Parallel arrays, the first {@link #carried_count} entries; the payloads
140
+ * are from the pool.
141
+ */
142
+ #carried_count = 0;
143
+ #carried_type_ids = /** @type {number[]} */ ([]);
144
+ #carried_payloads = /** @type {Uint8Array[]} */ ([]);
145
+ #carried_lengths = /** @type {number[]} */ ([]);
146
+
147
+ // The input of the frame being opened — its history, its pending records, the local queue —
148
+ // before it is put in sender order. Parallel arrays, the first #sort_count entries.
149
+ #sort_count = 0;
150
+ #sort_senders = /** @type {number[]} */ ([]);
151
+ #sort_type_ids = /** @type {number[]} */ ([]);
152
+ #sort_payloads = /** @type {Uint8Array[]} */ ([]);
153
+ #sort_lengths = /** @type {number[]} */ ([]);
154
+ // whether the payload is the frame's own copy, from the pool, to give back once applied
155
+ #sort_pooled = /** @type {boolean[]} */ ([]);
156
+
157
+ /**
158
+ * The frame's input in the order it is applied: indices into the sort arrays, by sender, and
159
+ * within a sender in the order they were added.
160
+ * @type {Int32Array}
161
+ */
162
+ #sort_order = new Int32Array(64);
163
+
164
+ /**
165
+ * Counting-sort scratch: per sender byte, where its records start in {@link #sort_order}.
166
+ * @type {Int32Array}
124
167
  */
125
- #carried_scratch = [];
126
- #sort_scratch = /** @type {Array<{sender_id:number, type_id:number, payload:Uint8Array}>} */ ([]);
168
+ #sort_sender_starts = new Int32Array(257);
169
+
127
170
  #payload_buf;
128
171
  // Walks a frame's records, for the history read.
129
172
  #cursor = new ActionRecordCursor();
@@ -377,9 +420,7 @@ export class ServerAuthoritativeServer {
377
420
  // accumulate in pending until tick() drains them.
378
421
  this.peer.replicator.on_pending_action = (peer_id, frame_number, type_id, buf, off, len, ordinal) => {
379
422
  assert.isNonNegativeInteger(ordinal, 'ordinal');
380
- const payload = new Uint8Array(len);
381
- payload.set(buf.raw_bytes.subarray(off, off + len));
382
- this.#pending_add(frame_number, ordinal, peer_id, type_id, payload);
423
+ this.#pending_add(frame_number, ordinal, peer_id, type_id, buf.raw_bytes, off, len);
383
424
  if (frame_number > this.last_client_frame_processed) {
384
425
  this.last_client_frame_processed = frame_number;
385
426
  }
@@ -641,7 +682,7 @@ export class ServerAuthoritativeServer {
641
682
 
642
683
  // 1. Drop pending entries outside the action_log's rewindable window.
643
684
  const window_oldest = Math.max(0, sim_frame - this.action_log.frame_capacity + 1);
644
- if (this.#pending_frames.length > 0 && this.#pending_referenced_frames[0] < window_oldest) {
685
+ if (this.#pending_oldest_frame < window_oldest) {
645
686
  this.#pending_trim_to_window(window_oldest);
646
687
  }
647
688
 
@@ -655,12 +696,10 @@ export class ServerAuthoritativeServer {
655
696
  // hold — a retransmission of an applied record is dropped on
656
697
  // arrival, see __pending_add — so the oldest pending frame is the
657
698
  // oldest frame whose outcome can change, and a rewind to it is
658
- // never wasted. `__pending_referenced_frames` is sorted
659
- // ascending; entries `> sim_frame` stay buffered.
699
+ // never wasted. Entries `> sim_frame` stay buffered.
660
700
  let replay_start = sim_frame;
661
- const refs = this.#pending_referenced_frames;
662
- if (refs.length > 0 && refs[0] <= sim_frame) {
663
- replay_start = refs[0];
701
+ if (this.#pending_oldest_frame <= sim_frame) {
702
+ replay_start = this.#pending_oldest_frame;
664
703
  }
665
704
 
666
705
  try {
@@ -768,29 +807,29 @@ export class ServerAuthoritativeServer {
768
807
  * @private
769
808
  */
770
809
  #open_frame(f, fresh) {
771
- this.#sort_scratch.length = 0;
810
+ // also gives back what a frame that did not finish left behind
811
+ this.#sort_reset();
772
812
 
773
813
  // Read historical actions out of action_log[f] BEFORE begin_frame(f)
774
814
  // recycles the buffer. The sender_id is recorded per-record (see
775
815
  // SimActionExecutor), so the stable sort below produces deterministic
776
816
  // order regardless of how history was originally interleaved.
777
- this.#read_historical(f, this.#historical_scratch);
778
- for (let i = 0; i < this.#historical_scratch.length; i++) {
779
- const h = this.#historical_scratch[i];
780
- this.#sort_scratch.push({ sender_id: h.sender_id, type_id: h.type_id, payload: h.payload });
781
- }
817
+ this.#read_historical(f);
782
818
 
783
819
  // Append the pending actions for this frame. Pending holds only records that had not
784
820
  // arrived before (see #pending_add): a copy of what the log already holds is recognised on
785
821
  // arrival by its identity and never gets here, so nothing in it duplicates history. Nothing
786
822
  // is compared by bytes — two records alike in every byte are two records (a held key).
787
- for (let i = 0; i < this.#pending_frames.length; i++) {
823
+ const pending_count = this.#pending_count;
824
+ for (let i = 0; i < pending_count; i++) {
788
825
  if (this.#pending_frames[i] !== f) continue;
789
- this.#sort_scratch.push({
790
- sender_id: this.#pending_senders[i],
791
- type_id: this.#pending_type_ids[i],
792
- payload: this.#pending_payloads[i],
793
- });
826
+ this.#sort_push(
827
+ this.#pending_senders[i],
828
+ this.#pending_type_ids[i],
829
+ this.#pending_payloads[i],
830
+ this.#pending_lengths[i],
831
+ false,
832
+ );
794
833
  }
795
834
 
796
835
  // Locally-authored actions join the merge as input, and only on the
@@ -803,27 +842,138 @@ export class ServerAuthoritativeServer {
803
842
  if (fresh && this.#local_type_ids.length > 0) {
804
843
  const sender = this.server_peer_id >= 0 ? this.server_peer_id : SENDER_LOCAL;
805
844
  for (let i = 0; i < this.#local_type_ids.length; i++) {
806
- this.#sort_scratch.push({
807
- sender_id: sender,
808
- type_id: this.#local_type_ids[i],
809
- payload: this.#local_payloads[i],
810
- });
845
+ const payload = this.#local_payloads[i];
846
+
847
+ this.#sort_push(sender, this.#local_type_ids[i], payload, payload.length, false);
811
848
  }
812
849
  this.#local_type_ids.length = 0;
813
850
  this.#local_payloads.length = 0;
814
851
  }
815
852
 
816
- // Stable sort by sender. Array.prototype.sort is stable since ES2019;
817
- // equal sender_ids preserve insertion order, with historical entries
818
- // appearing before newly-arrived pending entries for the same sender.
819
- this.#sort_scratch.sort((a, b) => a.sender_id - b.sender_id);
853
+ // Stable order by sender: equal sender_ids keep the order they were added in, with
854
+ // historical entries appearing before newly-arrived pending entries for the same sender.
855
+ this.#sort_by_sender();
820
856
 
821
857
  // Open the frame, execute all.
822
858
  this.action_log.begin_frame(f);
823
- for (let i = 0; i < this.#sort_scratch.length; i++) {
824
- const s = this.#sort_scratch[i];
825
- this.#apply_payload(s.type_id, s.sender_id, s.payload);
859
+
860
+ const count = this.#sort_count;
861
+ const order = this.#sort_order;
862
+
863
+ for (let i = 0; i < count; i++) {
864
+ const k = order[i];
865
+
866
+ this.#apply_payload(this.#sort_type_ids[k], this.#sort_senders[k], this.#sort_payloads[k], this.#sort_lengths[k]);
826
867
  }
868
+
869
+ this.#sort_reset();
870
+ }
871
+
872
+ /**
873
+ * Add a record to the input of the frame being opened.
874
+ *
875
+ * @param {number} sender_id a sender byte, `[0, 255]`
876
+ * @param {number} type_id
877
+ * @param {Uint8Array} payload
878
+ * @param {number} length how many of `payload`'s bytes are the record
879
+ * @param {boolean} pooled the payload is the frame's own copy, to give back once applied
880
+ * @private
881
+ */
882
+ #sort_push(sender_id, type_id, payload, length, pooled) {
883
+ const index = this.#sort_count++;
884
+
885
+ this.#sort_senders[index] = sender_id;
886
+ this.#sort_type_ids[index] = type_id;
887
+ this.#sort_payloads[index] = payload;
888
+ this.#sort_lengths[index] = length;
889
+ this.#sort_pooled[index] = pooled;
890
+ }
891
+
892
+ /**
893
+ * Empty the frame's input, giving back the payloads that were its own copies.
894
+ * @private
895
+ */
896
+ #sort_reset() {
897
+ const count = this.#sort_count;
898
+
899
+ for (let i = 0; i < count; i++) {
900
+ if (this.#sort_pooled[i]) {
901
+ this.#payload_release(this.#sort_payloads[i]);
902
+ }
903
+ }
904
+
905
+ this.#sort_count = 0;
906
+ }
907
+
908
+ /**
909
+ * Fill {@link #sort_order} with the frame's input by sender, keeping, within a sender, the
910
+ * order the records were added in. A counting sort over the sender byte: linear in the records,
911
+ * and nothing is allocated unless the frame holds more records than any before it.
912
+ * @private
913
+ */
914
+ #sort_by_sender() {
915
+ const count = this.#sort_count;
916
+ const senders = this.#sort_senders;
917
+ const starts = this.#sort_sender_starts;
918
+
919
+ if (this.#sort_order.length < count) {
920
+ this.#sort_order = new Int32Array(Math.max(count, this.#sort_order.length * 2));
921
+ }
922
+
923
+ const order = this.#sort_order;
924
+
925
+ starts.fill(0);
926
+
927
+ // how many records each sender has, one slot along...
928
+ for (let i = 0; i < count; i++) {
929
+ starts[senders[i] + 1]++;
930
+ }
931
+
932
+ // ...summed, is where each sender's records start
933
+ for (let s = 0; s < 256; s++) {
934
+ starts[s + 1] += starts[s];
935
+ }
936
+
937
+ for (let i = 0; i < count; i++) {
938
+ order[starts[senders[i]]++] = i;
939
+ }
940
+ }
941
+
942
+ /**
943
+ * A byte array of at least `length` bytes for a record's payload, from the pool when it has
944
+ * one long enough on top. One that is too short is let go of, so the pool's arrays grow to the
945
+ * records that pass through it.
946
+ *
947
+ * @param {number} length
948
+ * @returns {Uint8Array}
949
+ * @private
950
+ */
951
+ #payload_acquire(length) {
952
+ const count = this.#payload_pool_count;
953
+
954
+ if (count > 0) {
955
+ const pool = this.#payload_pool;
956
+ const top = pool[count - 1];
957
+
958
+ pool[count - 1] = null;
959
+ this.#payload_pool_count = count - 1;
960
+
961
+ if (top.length >= length) {
962
+ return top;
963
+ }
964
+ }
965
+
966
+ return new Uint8Array(length);
967
+ }
968
+
969
+ /**
970
+ * Give a payload array back to the pool. The caller no longer reads it.
971
+ *
972
+ * @param {Uint8Array} payload
973
+ * @private
974
+ */
975
+ #payload_release(payload) {
976
+ this.#payload_pool[this.#payload_pool_count++] = payload;
827
977
  }
828
978
 
829
979
  /**
@@ -865,21 +1015,23 @@ export class ServerAuthoritativeServer {
865
1015
  * @private
866
1016
  */
867
1017
  #record_carried() {
868
- const carried = this.#carried_scratch;
1018
+ const count = this.#carried_count;
869
1019
 
870
- for (let i = 0; i < carried.length; i++) {
871
- const { type_id, payload } = carried[i];
1020
+ for (let i = 0; i < count; i++) {
1021
+ const type_id = this.#carried_type_ids[i];
1022
+ const payload = this.#carried_payloads[i];
1023
+ const length = this.#carried_lengths[i];
872
1024
 
873
1025
  const klass = this.action_registry.klass_for(type_id);
874
1026
  if (klass === undefined) continue;
875
1027
 
876
1028
  const action = this.action_registry.acquire(klass);
877
1029
  try {
878
- if (this.#payload_buf.raw_bytes.length < payload.length) {
879
- this.#payload_buf.setCapacity(payload.length);
1030
+ if (this.#payload_buf.raw_bytes.length < length) {
1031
+ this.#payload_buf.setCapacity(length);
880
1032
  }
881
1033
  this.#payload_buf.position = 0;
882
- this.#payload_buf.writeBytes(payload, 0, payload.length);
1034
+ this.#payload_buf.writeBytes(payload, 0, length);
883
1035
  this.#payload_buf.position = 0;
884
1036
  action.deserialize(this.#payload_buf);
885
1037
  this.executor.record(action);
@@ -888,7 +1040,21 @@ export class ServerAuthoritativeServer {
888
1040
  }
889
1041
  }
890
1042
 
891
- carried.length = 0;
1043
+ this.#carried_reset();
1044
+ }
1045
+
1046
+ /**
1047
+ * Empty the carried records, giving their payloads back.
1048
+ * @private
1049
+ */
1050
+ #carried_reset() {
1051
+ const count = this.#carried_count;
1052
+
1053
+ for (let i = 0; i < count; i++) {
1054
+ this.#payload_release(this.#carried_payloads[i]);
1055
+ }
1056
+
1057
+ this.#carried_count = 0;
892
1058
  }
893
1059
 
894
1060
  /**
@@ -896,18 +1062,23 @@ export class ServerAuthoritativeServer {
896
1062
  * — is reported and passed over: the executor leaves nothing of it behind, and the rest of the
897
1063
  * frame's input, and the frame itself, go ahead. Letting it escape would leave the frame open
898
1064
  * with nothing left to close it.
1065
+ *
1066
+ * @param {number} type_id
1067
+ * @param {number} sender_id
1068
+ * @param {Uint8Array} payload
1069
+ * @param {number} length how many of `payload`'s bytes are the record
899
1070
  * @private
900
1071
  */
901
- #apply_payload(type_id, sender_id, payload) {
1072
+ #apply_payload(type_id, sender_id, payload, length) {
902
1073
  const klass = this.action_registry.klass_for(type_id);
903
1074
  if (klass === undefined) return;
904
1075
  const action = this.action_registry.acquire(klass);
905
1076
  try {
906
- if (this.#payload_buf.raw_bytes.length < payload.length) {
907
- this.#payload_buf.setCapacity(payload.length);
1077
+ if (this.#payload_buf.raw_bytes.length < length) {
1078
+ this.#payload_buf.setCapacity(length);
908
1079
  }
909
1080
  this.#payload_buf.position = 0;
910
- this.#payload_buf.writeBytes(payload, 0, payload.length);
1081
+ this.#payload_buf.writeBytes(payload, 0, length);
911
1082
  this.#payload_buf.position = 0;
912
1083
  action.deserialize(this.#payload_buf);
913
1084
  this.executor.execute(action, sender_id);
@@ -918,10 +1089,17 @@ export class ServerAuthoritativeServer {
918
1089
  }
919
1090
  }
920
1091
 
921
- /** @private */
922
- #read_historical(frame_number, out_array) {
923
- out_array.length = 0;
924
- this.#carried_scratch.length = 0;
1092
+ /**
1093
+ * Read frame `frame_number`'s records out of the log, before the frame is reopened over them:
1094
+ * its input into the frame's input ({@link #sort_push}), what was recorded and not executed
1095
+ * into the carried records. Each payload is copied into an array from the pool.
1096
+ *
1097
+ * @param {number} frame_number
1098
+ * @private
1099
+ */
1100
+ #read_historical(frame_number) {
1101
+ // also gives back what a frame that never recorded its carried records left behind
1102
+ this.#carried_reset();
925
1103
  if (!this.action_log.has_frame(frame_number)) return;
926
1104
  const cursor = this.#cursor;
927
1105
  cursor.open(this.action_log, frame_number);
@@ -934,17 +1112,28 @@ export class ServerAuthoritativeServer {
934
1112
  // effect twice, and the copies would accumulate one per replay.
935
1113
  if (cursor.sender_id === SENDER_DERIVED) continue;
936
1114
 
937
- const payload = new Uint8Array(cursor.payload_len);
938
- payload.set(bytes.subarray(cursor.payload_start, cursor.payload_start + cursor.payload_len));
1115
+ const length = cursor.payload_len;
1116
+ const start = cursor.payload_start;
1117
+
1118
+ const payload = this.#payload_acquire(length);
1119
+
1120
+ for (let i = 0; i < length; i++) {
1121
+ payload[i] = bytes[start + i];
1122
+ }
939
1123
 
940
1124
  // A record of what the engine's systems produced — the host publishing its physics, say.
941
1125
  // Neither input to reapply nor output the replay recomputes: carried over as it is.
942
1126
  if (cursor.sender_id === SENDER_RECORDED) {
943
- this.#carried_scratch.push({ type_id: cursor.action_type_id, payload });
1127
+ const index = this.#carried_count++;
1128
+
1129
+ this.#carried_type_ids[index] = cursor.action_type_id;
1130
+ this.#carried_payloads[index] = payload;
1131
+ this.#carried_lengths[index] = length;
1132
+
944
1133
  continue;
945
1134
  }
946
1135
 
947
- out_array.push({ type_id: cursor.action_type_id, sender_id: cursor.sender_id, payload });
1136
+ this.#sort_push(cursor.sender_id, cursor.action_type_id, payload, length, true);
948
1137
  }
949
1138
  }
950
1139
 
@@ -980,10 +1169,12 @@ export class ServerAuthoritativeServer {
980
1169
  * @param {number} ordinal the record's index in the sender's frame, from the wire
981
1170
  * @param {number} sender_id
982
1171
  * @param {number} type_id
983
- * @param {Uint8Array} payload
1172
+ * @param {Uint8Array} bytes the buffer the record arrived in; copied only if the record is taken
1173
+ * @param {number} offset where the record's payload starts in `bytes`
1174
+ * @param {number} length the payload's length
984
1175
  * @private
985
1176
  */
986
- #pending_add(frame_number, ordinal, sender_id, type_id, payload) {
1177
+ #pending_add(frame_number, ordinal, sender_id, type_id, bytes, offset, length) {
987
1178
  const ring = this.#arrival_ring_for(sender_id);
988
1179
 
989
1180
  // A copy first — already pending, already in the log, or already folded into a later
@@ -1024,18 +1215,32 @@ export class ServerAuthoritativeServer {
1024
1215
  }
1025
1216
  // Absolute backstop on buffered entries: within the window and the
1026
1217
  // ordinal bound a peer can still pile up distinct entries.
1027
- if (this.#pending_frames.length >= this.max_pending_total) {
1218
+ if (this.#pending_count >= this.max_pending_total) {
1028
1219
  this.#drop_pending(sender_id, frame_number, 'capacity');
1029
1220
  return;
1030
1221
  }
1031
1222
 
1032
1223
  ring.mark(frame_number, ordinal);
1033
1224
 
1034
- this.#pending_frames.push(frame_number);
1035
- this.#pending_senders.push(sender_id);
1036
- this.#pending_type_ids.push(type_id);
1037
- this.#pending_payloads.push(payload);
1038
- this.#track_referenced_frame(frame_number);
1225
+ // Taken: only now is the payload copied out of the receive buffer. Most of what arrives is
1226
+ // a copy of a record already taken, and costs nothing.
1227
+ const payload = this.#payload_acquire(length);
1228
+
1229
+ for (let i = 0; i < length; i++) {
1230
+ payload[i] = bytes[offset + i];
1231
+ }
1232
+
1233
+ const index = this.#pending_count++;
1234
+
1235
+ this.#pending_frames[index] = frame_number;
1236
+ this.#pending_senders[index] = sender_id;
1237
+ this.#pending_type_ids[index] = type_id;
1238
+ this.#pending_payloads[index] = payload;
1239
+ this.#pending_lengths[index] = length;
1240
+
1241
+ if (frame_number < this.#pending_oldest_frame) {
1242
+ this.#pending_oldest_frame = frame_number;
1243
+ }
1039
1244
  }
1040
1245
 
1041
1246
  /**
@@ -1078,47 +1283,55 @@ export class ServerAuthoritativeServer {
1078
1283
  }
1079
1284
 
1080
1285
  /**
1081
- * Insert `frame_number` into the monotonically-sorted referenced-frames
1082
- * index, leaving it untouched if already present. Single source of truth
1083
- * for the three sites (per-add, post-trim, post-filter) that maintain
1084
- * this index, so the binary-search invariant and uniqueness check live
1085
- * in one place.
1086
- * @param {number} frame_number
1286
+ * Keep the pending entries tagged for a frame of at least `oldest_kept`, in their order, and
1287
+ * give the payloads of the rest back to the pool. {@link #pending_oldest_frame} follows.
1288
+ *
1289
+ * @param {number} oldest_kept
1290
+ * @param {boolean} report report each entry dropped (`'window'`)
1087
1291
  * @private
1088
1292
  */
1089
- #track_referenced_frame(frame_number) {
1090
- const arr = this.#pending_referenced_frames;
1091
- const i = binarySearchHighIndex(arr, frame_number, number_compare_ascending);
1092
- if (arr[i] !== frame_number) arr.splice(i, 0, frame_number);
1093
- }
1293
+ #pending_keep_from(oldest_kept, report) {
1294
+ const count = this.#pending_count;
1094
1295
 
1095
- /**
1096
- * Drop every pending entry tagged below `window_oldest` — input that waited in pending while the
1097
- * window moved past it — and report each (`'window'`).
1098
- * @param {number} window_oldest
1099
- * @private
1100
- */
1101
- #pending_trim_to_window(window_oldest) {
1102
1296
  let kept = 0;
1103
- for (let i = 0; i < this.#pending_frames.length; i++) {
1104
- if (this.#pending_frames[i] >= window_oldest) {
1105
- this.#pending_frames[kept] = this.#pending_frames[i];
1297
+ let oldest = Infinity;
1298
+
1299
+ for (let i = 0; i < count; i++) {
1300
+ const frame = this.#pending_frames[i];
1301
+
1302
+ if (frame >= oldest_kept) {
1303
+ this.#pending_frames[kept] = frame;
1106
1304
  this.#pending_senders[kept] = this.#pending_senders[i];
1107
1305
  this.#pending_type_ids[kept] = this.#pending_type_ids[i];
1108
1306
  this.#pending_payloads[kept] = this.#pending_payloads[i];
1307
+ this.#pending_lengths[kept] = this.#pending_lengths[i];
1109
1308
  kept++;
1309
+
1310
+ if (frame < oldest) oldest = frame;
1110
1311
  } else {
1111
- this.#drop_pending(this.#pending_senders[i], this.#pending_frames[i], 'window');
1312
+ // read before the report: a listener must not find the entry half gone
1313
+ const sender = this.#pending_senders[i];
1314
+
1315
+ this.#payload_release(this.#pending_payloads[i]);
1316
+
1317
+ if (report) {
1318
+ this.#drop_pending(sender, frame, 'window');
1319
+ }
1112
1320
  }
1113
1321
  }
1114
- this.#pending_frames.length = kept;
1115
- this.#pending_senders.length = kept;
1116
- this.#pending_type_ids.length = kept;
1117
- this.#pending_payloads.length = kept;
1118
- this.#pending_referenced_frames.length = 0;
1119
- for (const f of this.#pending_frames) {
1120
- this.#track_referenced_frame(f);
1121
- }
1322
+
1323
+ this.#pending_count = kept;
1324
+ this.#pending_oldest_frame = oldest;
1325
+ }
1326
+
1327
+ /**
1328
+ * Drop every pending entry tagged below `window_oldest` — input that waited in pending while the
1329
+ * window moved past it — and report each (`'window'`).
1330
+ * @param {number} window_oldest
1331
+ * @private
1332
+ */
1333
+ #pending_trim_to_window(window_oldest) {
1334
+ this.#pending_keep_from(window_oldest, true);
1122
1335
  }
1123
1336
 
1124
1337
  /**
@@ -1131,56 +1344,28 @@ export class ServerAuthoritativeServer {
1131
1344
  */
1132
1345
  #pending_fold_late_into(sim_frame) {
1133
1346
  const frames = this.#pending_frames;
1134
- let folded_any = false;
1347
+ const count = this.#pending_count;
1135
1348
 
1136
- for (let i = 0; i < frames.length; i++) {
1137
- if (frames[i] >= sim_frame) continue;
1138
- frames[i] = sim_frame;
1139
- folded_any = true;
1140
- }
1349
+ let oldest = Infinity;
1141
1350
 
1142
- if (folded_any) {
1143
- this.#pending_referenced_frames.length = 0;
1144
- for (const f of frames) {
1145
- this.#track_referenced_frame(f);
1351
+ for (let i = 0; i < count; i++) {
1352
+ if (frames[i] < sim_frame) {
1353
+ frames[i] = sim_frame;
1146
1354
  }
1355
+
1356
+ if (frames[i] < oldest) oldest = frames[i];
1147
1357
  }
1148
- }
1149
1358
 
1150
- /** @private */
1151
- #pending_clear() {
1152
- this.#pending_frames.length = 0;
1153
- this.#pending_senders.length = 0;
1154
- this.#pending_type_ids.length = 0;
1155
- this.#pending_payloads.length = 0;
1156
- this.#pending_referenced_frames.length = 0;
1359
+ this.#pending_oldest_frame = oldest;
1157
1360
  }
1158
1361
 
1159
1362
  /**
1160
1363
  * Drop pending entries with `frame <= keep_threshold`, keeping the
1161
- * rest. Same structural pattern as {@link __pending_trim_to_window}
1162
- * but with the inequality flipped — used at the end of {@link tick}
1364
+ * rest: they have been applied. Used at the end of {@link tick}
1163
1365
  * to retain future-tagged inputs under `simulation_delay_ticks > 0`.
1164
1366
  * @private
1165
1367
  */
1166
1368
  #pending_filter_to_future(keep_threshold) {
1167
- let kept = 0;
1168
- for (let i = 0; i < this.#pending_frames.length; i++) {
1169
- if (this.#pending_frames[i] > keep_threshold) {
1170
- this.#pending_frames[kept] = this.#pending_frames[i];
1171
- this.#pending_senders[kept] = this.#pending_senders[i];
1172
- this.#pending_type_ids[kept] = this.#pending_type_ids[i];
1173
- this.#pending_payloads[kept] = this.#pending_payloads[i];
1174
- kept++;
1175
- }
1176
- }
1177
- this.#pending_frames.length = kept;
1178
- this.#pending_senders.length = kept;
1179
- this.#pending_type_ids.length = kept;
1180
- this.#pending_payloads.length = kept;
1181
- this.#pending_referenced_frames.length = 0;
1182
- for (const f of this.#pending_frames) {
1183
- this.#track_referenced_frame(f);
1184
- }
1369
+ this.#pending_keep_from(keep_threshold + 1, false);
1185
1370
  }
1186
1371
  }
@@ -226,7 +226,10 @@ export class SimActionExecutor {
226
226
  *
227
227
  * Not re-entrant: calling `execute` or {@link record} from inside `affected_components`,
228
228
  * {@link authorize}, `apply`, `announce` or {@link on_component_written} is illegal (the
229
- * executor is passed to actions for `slot_table` / `current_sender_id` reads only).
229
+ * executor is passed to actions for `slot_table` / `current_sender_id` reads only), and
230
+ * asserted. Unchecked, the inner action takes over the outer one's list of affected components:
231
+ * started from `affected_components`, the outer action's prior state is captured for the inner
232
+ * action's entity and a rewind no longer restores its own.
230
233
  *
231
234
  * @param {SimAction} action
232
235
  * @param {number} [sender_id] peer that originated this action.