@woosh/meep-engine 3.64.1 → 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.
- package/CHANGELOG.md +85 -0
- package/build/bundle-worker-image-decoder.js +1 -1
- package/build/bundle-worker-terrain.js +1 -1
- package/package.json +1 -1
- package/src/core/binary/BinaryBuffer.d.ts +5 -0
- package/src/core/binary/BinaryBuffer.d.ts.map +1 -1
- package/src/core/binary/BinaryBuffer.js +39 -5
- package/src/core/geom/3d/topology/struct/binary/io/bt_boundary_loop.d.ts +65 -6
- package/src/core/geom/3d/topology/struct/binary/io/bt_boundary_loop.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_boundary_loop.js +451 -101
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.d.ts +4 -2
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.js +4 -2
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.d.ts +8 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_fill_small_holes.js +45 -10
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_face_find_path_polyanya.js +237 -119
- package/src/engine/graphics/ecs/grass/GrassSpecies.d.ts +143 -0
- package/src/engine/graphics/ecs/grass/GrassSpecies.d.ts.map +1 -0
- package/src/engine/graphics/ecs/grass/GrassSpecies.js +189 -0
- package/src/engine/graphics/ecs/grass/GrassSurface.d.ts +25 -0
- package/src/engine/graphics/ecs/grass/GrassSurface.d.ts.map +1 -0
- package/src/engine/graphics/ecs/grass/GrassSurface.js +32 -0
- package/src/engine/graphics/ecs/grass/GroundCover.d.ts +68 -0
- package/src/engine/graphics/ecs/grass/GroundCover.d.ts.map +1 -0
- package/src/engine/graphics/ecs/grass/GroundCover.js +85 -0
- package/src/engine/graphics3/GrassSurfaceSystem.d.ts +153 -0
- package/src/engine/graphics3/GrassSurfaceSystem.d.ts.map +1 -0
- package/src/engine/graphics3/GrassSurfaceSystem.js +1076 -0
- package/src/engine/graphics3/GroundCoverSystem.d.ts +33 -0
- package/src/engine/graphics3/GroundCoverSystem.d.ts.map +1 -0
- package/src/engine/graphics3/GroundCoverSystem.js +58 -0
- package/src/engine/network/NetworkSession.d.ts.map +1 -1
- package/src/engine/network/NetworkSession.js +372 -110
- package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/NetworkPeer.js +6 -1
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts.map +1 -1
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.js +9 -2
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.js +325 -140
- package/src/engine/network/sim/SimActionExecutor.d.ts +4 -1
- package/src/engine/network/sim/SimActionExecutor.d.ts.map +1 -1
- package/src/engine/network/sim/SimActionExecutor.js +65 -9
- package/src/engine/network/state/PredictionHistory.d.ts.map +1 -1
- package/src/engine/network/state/PredictionHistory.js +6 -1
- package/src/engine/network/time/AdaptiveRenderDelay.d.ts +25 -14
- package/src/engine/network/time/AdaptiveRenderDelay.d.ts.map +1 -1
- package/src/engine/network/time/AdaptiveRenderDelay.js +38 -20
- package/src/engine/network/time/RenderPlayout.d.ts +23 -3
- package/src/engine/network/time/RenderPlayout.d.ts.map +1 -1
- package/src/engine/network/time/RenderPlayout.js +40 -4
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/engine/physics/fluid/obstacle/chunk_fluid_obstacle_record.d.ts +5 -1
- package/src/engine/physics/fluid/obstacle/chunk_fluid_obstacle_record.d.ts.map +1 -1
- package/src/engine/physics/fluid/obstacle/chunk_fluid_obstacle_record.js +27 -1
- package/src/shade/device/shader/ShaderModuleCompiler.d.ts +2 -0
- package/src/shade/device/shader/ShaderModuleCompiler.d.ts.map +1 -1
- package/src/shade/device/shader/ShaderModuleCompiler.js +25 -2
- package/src/shade/playground/grass_surfaces/index.html +75 -0
- package/src/shade/playground/grass_surfaces/main.d.ts +2 -0
- package/src/shade/playground/grass_surfaces/main.d.ts.map +1 -0
- package/src/shade/playground/grass_surfaces/main.js +593 -0
- package/src/shade/playground/grass_surfaces/read_grass_surfaces.d.ts +62 -0
- package/src/shade/playground/grass_surfaces/read_grass_surfaces.d.ts.map +1 -0
- package/src/shade/playground/grass_surfaces/read_grass_surfaces.js +188 -0
- package/src/shade/playground/probe_clipmap_box/README.md +5 -1
- package/src/shade/playground/probe_clipmap_box/index.html +12 -0
- package/src/shade/playground/probe_clipmap_box/main.d.ts.map +1 -1
- package/src/shade/playground/probe_clipmap_box/main.js +15 -0
- package/src/shade/playground/probe_clipmap_box/scene.d.ts +8 -1
- package/src/shade/playground/probe_clipmap_box/scene.d.ts.map +1 -1
- package/src/shade/playground/probe_clipmap_box/scene.js +74 -6
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +47 -43
- package/src/shade/renderer/extension/ViewTextures.d.ts +12 -5
- package/src/shade/renderer/extension/ViewTextures.d.ts.map +1 -1
- package/src/shade/renderer/extension/ViewTextures.js +19 -5
- package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts +3 -1
- package/src/shade/renderer/fluid/GPUFluidCascadeStack.d.ts.map +1 -1
- package/src/shade/renderer/fluid/GPUFluidCascadeStack.js +6 -1
- package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts +7 -0
- package/src/shade/renderer/fluid/forcing/GPUFluidForcing.d.ts.map +1 -1
- package/src/shade/renderer/fluid/forcing/GPUFluidForcing.js +10 -0
- package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts +7 -1
- package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/GPUGeometrySDFManager.js +46 -15
- package/src/shade/renderer/geometry/sdf/bundle/ModelCacheBundle.d.ts +3 -2
- package/src/shade/renderer/geometry/sdf/bundle/ModelCacheBundle.d.ts.map +1 -1
- package/src/shade/renderer/geometry/sdf/bundle/ModelCacheBundle.js +3 -2
- package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_sort_morton.d.ts +22 -0
- package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_sort_morton.d.ts.map +1 -0
- package/src/shade/renderer/geometry/sdf/bundle/model_cache_bundle_sort_morton.js +247 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts +50 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/GPUProbeClipmapGI.js +101 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts +2 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/ProbeClipmapSettings.js +2 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.d.ts +8 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/GPUBrickClipmap.js +12 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.d.ts +12 -6
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/brick/chunk_brick_clipmap_trace.js +35 -29
- package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_clipmap.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_clipmap.js +4 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_material.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/debug/graph_probe_clipmap_debug_brick_material.js +6 -4
- package/src/shade/renderer/global_illumination/probe_clipmap/material/GPUBrickMaterial.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/material/GPUBrickMaterial.js +2 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material.d.ts +6 -5
- package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/material/chunk_brick_material.js +15 -14
- package/src/shade/renderer/global_illumination/probe_clipmap/material/shader_brick_material_gather.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/material/shader_brick_material_gather.js +4 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts +19 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/GPUProbeClipmap.js +128 -10
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts +19 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/PROBE_CLIPMAP.js +27 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/ProbeClipmapScreenWants.d.ts +19 -11
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/ProbeClipmapScreenWants.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/ProbeClipmapScreenWants.js +35 -11
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap.js +3 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_box_cages.d.ts +40 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_box_cages.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_box_cages.js +174 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_material.d.ts +4 -4
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_hit_material.js +10 -10
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_parallax.d.ts +31 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_parallax.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_parallax.js +54 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts +8 -4
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_sample_radiance.js +10 -21
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.d.ts +7 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/chunk_probe_clipmap_want.js +33 -29
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/graph_probe_clipmap_want_meshlets.d.ts +28 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/graph_probe_clipmap_want_meshlets.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/graph_probe_clipmap_want_meshlets.js +138 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.d.ts +13 -9
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_due.js +18 -11
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_light.js +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_relocate.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_relocate.js +4 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_retire.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_retire.js +2 -3
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_schedule.d.ts +5 -3
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_schedule.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_schedule.js +15 -30
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_shade.js +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_trace.js +4 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.d.ts +11 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want.js +29 -2
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_late.d.ts +40 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_late.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_late.js +126 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_meshlets.d.ts +36 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_meshlets.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe_clipmap/probe/shader_probe_clipmap_want_meshlets.js +221 -0
- package/src/shade/renderer/gpu_primitive/age_eviction/chunk_age_eviction.d.ts +40 -0
- package/src/shade/renderer/gpu_primitive/age_eviction/chunk_age_eviction.d.ts.map +1 -0
- package/src/shade/renderer/gpu_primitive/age_eviction/chunk_age_eviction.js +86 -0
- package/src/shade/renderer/grass/blade/GPUGrassBlades.d.ts +135 -0
- package/src/shade/renderer/grass/blade/GPUGrassBlades.d.ts.map +1 -0
- package/src/shade/renderer/grass/blade/GPUGrassBlades.js +676 -0
- package/src/shade/renderer/grass/blade/GRASS_BLADE.d.ts +145 -0
- package/src/shade/renderer/grass/blade/GRASS_BLADE.d.ts.map +1 -0
- package/src/shade/renderer/grass/blade/GRASS_BLADE.js +179 -0
- package/src/shade/renderer/grass/blade/chunk_grass_blade.d.ts +63 -0
- package/src/shade/renderer/grass/blade/chunk_grass_blade.d.ts.map +1 -0
- package/src/shade/renderer/grass/blade/chunk_grass_blade.js +244 -0
- package/src/shade/renderer/grass/blade/chunk_grass_blade_wind.d.ts +58 -0
- package/src/shade/renderer/grass/blade/chunk_grass_blade_wind.d.ts.map +1 -0
- package/src/shade/renderer/grass/blade/chunk_grass_blade_wind.js +174 -0
- package/src/shade/renderer/grass/blade/grass_blade_id_draw.d.ts +25 -0
- package/src/shade/renderer/grass/blade/grass_blade_id_draw.d.ts.map +1 -0
- package/src/shade/renderer/grass/blade/grass_blade_id_draw.js +133 -0
- package/src/shade/renderer/grass/blade/grass_blade_mechanics.d.ts +80 -0
- package/src/shade/renderer/grass/blade/grass_blade_mechanics.d.ts.map +1 -0
- package/src/shade/renderer/grass/blade/grass_blade_mechanics.js +92 -0
- package/src/shade/renderer/grass/blade/grass_blade_resolve.d.ts +29 -0
- package/src/shade/renderer/grass/blade/grass_blade_resolve.d.ts.map +1 -0
- package/src/shade/renderer/grass/blade/grass_blade_resolve.js +175 -0
- package/src/shade/renderer/grass/blade/shader_grass_blade_draw_args.d.ts +14 -0
- package/src/shade/renderer/grass/blade/shader_grass_blade_draw_args.d.ts.map +1 -0
- package/src/shade/renderer/grass/blade/shader_grass_blade_draw_args.js +45 -0
- package/src/shade/renderer/grass/blade/shader_grass_blade_expand.d.ts +61 -0
- package/src/shade/renderer/grass/blade/shader_grass_blade_expand.d.ts.map +1 -0
- package/src/shade/renderer/grass/blade/shader_grass_blade_expand.js +340 -0
- package/src/shade/renderer/grass/blade/shader_grass_cell_count.d.ts +46 -0
- package/src/shade/renderer/grass/blade/shader_grass_cell_count.d.ts.map +1 -0
- package/src/shade/renderer/grass/blade/shader_grass_cell_count.js +280 -0
- package/src/shade/renderer/grass/population/chunk_grass_population.d.ts +60 -0
- package/src/shade/renderer/grass/population/chunk_grass_population.d.ts.map +1 -0
- package/src/shade/renderer/grass/population/chunk_grass_population.js +171 -0
- package/src/shade/renderer/grass/press/GPUGrassPress.d.ts +99 -0
- package/src/shade/renderer/grass/press/GPUGrassPress.d.ts.map +1 -0
- package/src/shade/renderer/grass/press/GPUGrassPress.js +436 -0
- package/src/shade/renderer/grass/press/GRASS_PRESS.d.ts +179 -0
- package/src/shade/renderer/grass/press/GRASS_PRESS.d.ts.map +1 -0
- package/src/shade/renderer/grass/press/GRASS_PRESS.js +217 -0
- package/src/shade/renderer/grass/press/chunk_grass_press.d.ts +65 -0
- package/src/shade/renderer/grass/press/chunk_grass_press.d.ts.map +1 -0
- package/src/shade/renderer/grass/press/chunk_grass_press.js +296 -0
- package/src/shade/renderer/grass/press/shader_grass_press_mark.d.ts +31 -0
- package/src/shade/renderer/grass/press/shader_grass_press_mark.d.ts.map +1 -0
- package/src/shade/renderer/grass/press/shader_grass_press_mark.js +169 -0
- package/src/shade/renderer/grass/press/shader_grass_press_stamp.d.ts +27 -0
- package/src/shade/renderer/grass/press/shader_grass_press_stamp.d.ts.map +1 -0
- package/src/shade/renderer/grass/press/shader_grass_press_stamp.js +183 -0
- package/src/shade/renderer/grass/surface/GPUGrassSurfaces.d.ts +193 -0
- package/src/shade/renderer/grass/surface/GPUGrassSurfaces.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/GPUGrassSurfaces.js +1253 -0
- package/src/shade/renderer/grass/surface/GRASS_SURFACE.d.ts +211 -0
- package/src/shade/renderer/grass/surface/GRASS_SURFACE.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/GRASS_SURFACE.js +241 -0
- package/src/shade/renderer/grass/surface/GRASS_SURFACE_VIEW.d.ts +82 -0
- package/src/shade/renderer/grass/surface/GRASS_SURFACE_VIEW.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/GRASS_SURFACE_VIEW.js +111 -0
- package/src/shade/renderer/grass/surface/chunk_grass_column_cross.d.ts +39 -0
- package/src/shade/renderer/grass/surface/chunk_grass_column_cross.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/chunk_grass_column_cross.js +85 -0
- package/src/shade/renderer/grass/surface/chunk_grass_directory.d.ts +29 -0
- package/src/shade/renderer/grass/surface/chunk_grass_directory.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/chunk_grass_directory.js +112 -0
- package/src/shade/renderer/grass/surface/chunk_grass_slot.d.ts +27 -0
- package/src/shade/renderer/grass/surface/chunk_grass_slot.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/chunk_grass_slot.js +50 -0
- package/src/shade/renderer/grass/surface/chunk_grass_surface_frame.d.ts +21 -0
- package/src/shade/renderer/grass/surface/chunk_grass_surface_frame.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/chunk_grass_surface_frame.js +41 -0
- package/src/shade/renderer/grass/surface/chunk_grass_surface_window.d.ts +32 -0
- package/src/shade/renderer/grass/surface/chunk_grass_surface_window.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/chunk_grass_surface_window.js +136 -0
- package/src/shade/renderer/grass/surface/chunk_grass_surfel.d.ts +37 -0
- package/src/shade/renderer/grass/surface/chunk_grass_surfel.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/chunk_grass_surfel.js +85 -0
- package/src/shade/renderer/grass/surface/chunk_grass_tile.d.ts +25 -0
- package/src/shade/renderer/grass/surface/chunk_grass_tile.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/chunk_grass_tile.js +52 -0
- package/src/shade/renderer/grass/surface/shader_grass_directory_fill.d.ts +23 -0
- package/src/shade/renderer/grass/surface/shader_grass_directory_fill.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/shader_grass_directory_fill.js +87 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_bake.d.ts +43 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_bake.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_bake.js +265 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_bake_command.d.ts +13 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_bake_command.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_bake_command.js +49 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_invalidate.d.ts +62 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_invalidate.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_invalidate.js +162 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_retire.d.ts +40 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_retire.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_retire.js +155 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_schedule.d.ts +19 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_schedule.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_schedule.js +58 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_want.d.ts +30 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_want.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_want.js +251 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_window_count.d.ts +21 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_window_count.d.ts.map +1 -0
- package/src/shade/renderer/grass/surface/shader_grass_surface_window_count.js +75 -0
- package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/velocity/graph_add_per_object_velocity.js +4 -23
- package/src/shade/renderer/postprocess/velocity/view_velocity_matrices.d.ts +12 -0
- package/src/shade/renderer/postprocess/velocity/view_velocity_matrices.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/velocity/view_velocity_matrices.js +29 -0
- package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/graph_rasterize_meshes_transparent_avboit.js +22 -0
- package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
- package/src/shade/renderer/scene/GPUSceneContext.js +3 -0
- package/src/shade/renderer/scene/GRASS_SURFACE_PARAMS_STRUCT.d.ts +27 -0
- package/src/shade/renderer/scene/GRASS_SURFACE_PARAMS_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/scene/GRASS_SURFACE_PARAMS_STRUCT.js +38 -0
- package/src/shade/renderer/scene/MESH_GROUND_COVER_STRUCT.d.ts +28 -0
- package/src/shade/renderer/scene/MESH_GROUND_COVER_STRUCT.d.ts.map +1 -0
- package/src/shade/renderer/scene/MESH_GROUND_COVER_STRUCT.js +58 -0
- package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.d.ts.map +1 -1
- package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.js +8 -0
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_nearest_among.d.ts +37 -0
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_nearest_among.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/geometry/ray/chunk_ray_query_nearest_among.js +148 -0
- package/src/shade/renderer/shader/chunk/sdf/chunk_shape_record_line_span.d.ts +20 -0
- package/src/shade/renderer/shader/chunk/sdf/chunk_shape_record_line_span.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/sdf/chunk_shape_record_line_span.js +169 -0
- package/src/shade/renderer/texture/atlas/chunk_tile_atlas_slot_origin.d.ts +18 -0
- package/src/shade/renderer/texture/atlas/chunk_tile_atlas_slot_origin.d.ts.map +1 -1
- package/src/shade/renderer/texture/atlas/chunk_tile_atlas_slot_origin.js +28 -0
- package/src/shade/renderer/texture/atlas/tile_atlas_slot_shift.d.ts +13 -0
- package/src/shade/renderer/texture/atlas/tile_atlas_slot_shift.d.ts.map +1 -0
- package/src/shade/renderer/texture/atlas/tile_atlas_slot_shift.js +22 -0
- package/src/shade/renderer/water/GPUWaterRenderer.d.ts.map +1 -1
- package/src/shade/renderer/water/GPUWaterRenderer.js +4 -0
- package/src/shade/renderer/wind/GPUSceneWind.d.ts +52 -5
- package/src/shade/renderer/wind/GPUSceneWind.d.ts.map +1 -1
- package/src/shade/renderer/wind/GPUSceneWind.js +164 -8
- package/src/shade/renderer/wind/WIND_FIELD_UNIFORM.d.ts +3 -1
- package/src/shade/renderer/wind/WIND_FIELD_UNIFORM.d.ts.map +1 -1
- package/src/shade/renderer/wind/WIND_FIELD_UNIFORM.js +3 -1
- package/src/shade/renderer/wind/chunk_wind_field_sample_cascades.d.ts +2 -1
- package/src/shade/renderer/wind/chunk_wind_field_sample_cascades.d.ts.map +1 -1
- package/src/shade/renderer/wind/chunk_wind_field_sample_cascades.js +18 -13
- package/src/shade/renderer/wind/chunk_wind_field_sample_previous.d.ts +13 -0
- package/src/shade/renderer/wind/chunk_wind_field_sample_previous.d.ts.map +1 -0
- package/src/shade/renderer/wind/chunk_wind_field_sample_previous.js +23 -0
- package/src/shade/renderer/wind/chunk_wind_field_sample_uniform.d.ts +1 -0
- package/src/shade/renderer/wind/chunk_wind_field_sample_uniform.d.ts.map +1 -1
- package/src/shade/renderer/wind/chunk_wind_field_sample_uniform.js +6 -1
- package/src/shade/renderer/wind/wind_field_add_resources.d.ts +11 -0
- package/src/shade/renderer/wind/wind_field_add_resources.d.ts.map +1 -1
- package/src/shade/renderer/wind/wind_field_add_resources.js +15 -0
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +1 -1
- package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
- 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
|
-
*
|
|
482
|
-
*
|
|
483
|
-
*
|
|
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
|
-
*
|
|
577
|
-
*
|
|
578
|
-
*
|
|
579
|
-
|
|
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
|
-
#
|
|
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
|
-
|
|
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.#
|
|
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.#
|
|
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.#
|
|
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
|
-
|
|
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.#
|
|
2708
|
+
this.#forget_pending_auth();
|
|
2511
2709
|
this.#reconciled_frame.clear();
|
|
2512
|
-
|
|
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.#
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
3301
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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
|
|
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,
|
|
3598
|
+
this.#reconciled_frame.set(network_id, frame);
|
|
3351
3599
|
try {
|
|
3352
|
-
this.#reconcile_entity(entity_id,
|
|
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 ${
|
|
3603
|
+
console.error(`NetworkSession: reconciling entity ${entity_id} to frame ${frame} failed:`, e);
|
|
3356
3604
|
}
|
|
3357
3605
|
}
|
|
3358
3606
|
|
|
3359
|
-
|
|
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 {
|
|
3617
|
+
* @param {PendingAuthState} state the host's state of the entity at `frame`
|
|
3370
3618
|
*/
|
|
3371
|
-
#reconcile_entity(entity_id, frame,
|
|
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
|
|
3378
|
-
|
|
3379
|
-
const
|
|
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
|
|
3383
|
-
if (
|
|
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(
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
3482
|
-
|
|
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
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
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
|
|
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,
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
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
|
-
|
|
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
|
|
3534
|
-
* @
|
|
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
|
-
* @
|
|
3809
|
+
* @param {number} offset
|
|
3810
|
+
* @param {number} length
|
|
3537
3811
|
*/
|
|
3538
|
-
#execute_recorded(type_id, bytes) {
|
|
3539
|
-
const
|
|
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 =
|
|
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,
|
|
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
|
-
|
|
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
|
|