@woosh/meep-engine 3.30.0 → 3.31.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/build/bundle-worker-image-decoder.js +1 -1
- package/build/bundle-worker-terrain.js +1 -1
- package/package.json +3 -1
- package/src/core/binary/BinaryBuffer.d.ts.map +1 -1
- package/src/core/binary/BinaryBuffer.js +42 -14
- package/src/core/binary/BitImage2.d.ts.map +1 -1
- package/src/core/binary/BitImage2.js +2 -6
- package/src/core/binary/BitSet.js +5 -5
- package/src/core/binary/compression/chunks_to_stream.d.ts +24 -0
- package/src/core/binary/compression/chunks_to_stream.d.ts.map +1 -0
- package/src/core/binary/compression/chunks_to_stream.js +35 -0
- package/src/core/binary/compression/compress_bytes.d.ts +3 -4
- package/src/core/binary/compression/compress_bytes.d.ts.map +1 -1
- package/src/core/binary/compression/compress_bytes.js +6 -17
- package/src/core/binary/compression/decompress_bytes.d.ts +1 -2
- package/src/core/binary/compression/decompress_bytes.d.ts.map +1 -1
- package/src/core/binary/compression/decompress_bytes.js +4 -15
- package/src/core/binary/compression/decompress_bytes_into.d.ts.map +1 -1
- package/src/core/binary/compression/decompress_bytes_into.js +2 -13
- package/src/core/binary/ctz32.d.ts +12 -4
- package/src/core/binary/ctz32.d.ts.map +1 -1
- package/src/core/binary/ctz32.js +23 -41
- package/src/core/binary/lsb_32.d.ts +10 -2
- package/src/core/binary/lsb_32.d.ts.map +1 -1
- package/src/core/binary/lsb_32.js +17 -12
- package/src/core/binary/lz4/lz4_compress_block_hc.js +2 -2
- package/src/core/binary/type/DataTypeIndices.d.ts +39 -0
- package/src/core/binary/type/DataTypeIndices.d.ts.map +1 -1
- package/src/core/binary/type/DataTypeIndices.js +38 -1
- package/src/core/binary/type/Type.d.ts.map +1 -1
- package/src/core/binary/type/Type.js +6 -1
- package/src/core/bvh2/bvh3/ebvh_optimize_treelet.js +3 -3
- package/src/core/bvh8/bvh8_geometry_validate.d.ts.map +1 -1
- package/src/core/bvh8/bvh8_geometry_validate.js +2 -88
- package/src/core/bvh8/bvh8_geometry_validate_bounds.d.ts +25 -0
- package/src/core/bvh8/bvh8_geometry_validate_bounds.d.ts.map +1 -0
- package/src/core/bvh8/bvh8_geometry_validate_bounds.js +105 -0
- package/src/core/bvh8/bvh8_geometry_validate_indirect.d.ts.map +1 -1
- package/src/core/bvh8/bvh8_geometry_validate_indirect.js +2 -91
- package/src/core/clipboard/obtainClipBoard.d.ts +4 -0
- package/src/core/clipboard/obtainClipBoard.d.ts.map +1 -1
- package/src/core/clipboard/obtainClipBoard.js +29 -8
- package/src/core/clipboard/safeClipboardReadText.d.ts.map +1 -1
- package/src/core/clipboard/safeClipboardReadText.js +73 -38
- package/src/core/clipboard/safeClipboardWriteText.d.ts.map +1 -1
- package/src/core/clipboard/safeClipboardWriteText.js +11 -9
- package/src/core/collection/array/iterator/ArrayIteratorRandom.d.ts.map +1 -1
- package/src/core/collection/array/iterator/ArrayIteratorRandom.js +6 -0
- package/src/core/collection/heap/IndexedFloatMinHeap.d.ts +6 -0
- package/src/core/collection/heap/IndexedFloatMinHeap.d.ts.map +1 -1
- package/src/core/collection/heap/IndexedFloatMinHeap.js +14 -0
- package/src/core/collection/list/FilteredListProjection.d.ts.map +1 -1
- package/src/core/collection/list/FilteredListProjection.js +7 -54
- package/src/core/collection/list/List.d.ts +4 -0
- package/src/core/collection/list/List.d.ts.map +1 -1
- package/src/core/collection/list/List.js +10 -52
- package/src/core/collection/list/SortedListProjection.d.ts +7 -0
- package/src/core/collection/list/SortedListProjection.d.ts.map +1 -1
- package/src/core/collection/list/SortedListProjection.js +12 -0
- package/src/core/collection/list/list_apply_ordered_diff.d.ts +37 -0
- package/src/core/collection/list/list_apply_ordered_diff.d.ts.map +1 -0
- package/src/core/collection/list/list_apply_ordered_diff.js +87 -0
- package/src/core/collection/map/BiMap.d.ts.map +1 -1
- package/src/core/collection/map/BiMap.js +19 -6
- package/src/core/collection/map/HashMap.d.ts.map +1 -1
- package/src/core/collection/map/HashMap.js +38 -11
- package/src/core/collection/queue/Deque.d.ts +2 -2
- package/src/core/collection/queue/Deque.d.ts.map +1 -1
- package/src/core/collection/queue/Deque.js +12 -1
- package/src/core/collection/table/RowFirstTable.d.ts.map +1 -1
- package/src/core/collection/table/RowFirstTable.js +15 -2
- package/src/core/collection/table/serializeRowFirstTable.d.ts.map +1 -1
- package/src/core/collection/table/serializeRowFirstTable.js +2 -3
- package/src/core/color/operations/color_lerp.d.ts.map +1 -1
- package/src/core/color/operations/color_lerp.js +77 -55
- package/src/core/color/sRGB/linear_to_sRGB.d.ts.map +1 -1
- package/src/core/color/sRGB/linear_to_sRGB.js +3 -1
- package/src/core/debug/matchers/AllOf.d.ts +2 -1
- package/src/core/debug/matchers/AllOf.d.ts.map +1 -1
- package/src/core/debug/matchers/AllOf.js +1 -1
- package/src/core/debug/matchers/AnyOf.d.ts +2 -1
- package/src/core/debug/matchers/AnyOf.d.ts.map +1 -1
- package/src/core/debug/matchers/AnyOf.js +1 -1
- package/src/core/debug/matchers/CombinableMatcher.d.ts +2 -1
- package/src/core/debug/matchers/CombinableMatcher.d.ts.map +1 -1
- package/src/core/debug/matchers/CombinableMatcher.js +1 -1
- package/src/core/debug/matchers/DescribeAs.d.ts +2 -1
- package/src/core/debug/matchers/DescribeAs.d.ts.map +1 -1
- package/src/core/debug/matchers/DescribeAs.js +2 -1
- package/src/core/debug/matchers/IsAnything.d.ts +2 -1
- package/src/core/debug/matchers/IsAnything.d.ts.map +1 -1
- package/src/core/debug/matchers/IsAnything.js +2 -1
- package/src/core/debug/matchers/IsEqual.d.ts +2 -1
- package/src/core/debug/matchers/IsEqual.d.ts.map +1 -1
- package/src/core/debug/matchers/IsEqual.js +2 -1
- package/src/core/debug/matchers/IsFinite.d.ts +2 -1
- package/src/core/debug/matchers/IsFinite.d.ts.map +1 -1
- package/src/core/debug/matchers/IsFinite.js +2 -1
- package/src/core/debug/matchers/IsIn.d.ts +2 -1
- package/src/core/debug/matchers/IsIn.d.ts.map +1 -1
- package/src/core/debug/matchers/IsIn.js +2 -1
- package/src/core/debug/matchers/IsInteger.d.ts +2 -1
- package/src/core/debug/matchers/IsInteger.d.ts.map +1 -1
- package/src/core/debug/matchers/IsInteger.js +2 -1
- package/src/core/debug/matchers/IsIterableContaining.d.ts +2 -1
- package/src/core/debug/matchers/IsIterableContaining.d.ts.map +1 -1
- package/src/core/debug/matchers/IsIterableContaining.js +1 -1
- package/src/core/debug/matchers/IsNot.d.ts +2 -1
- package/src/core/debug/matchers/IsNot.d.ts.map +1 -1
- package/src/core/debug/matchers/IsNot.js +2 -1
- package/src/core/debug/matchers/IsNull.d.ts +2 -1
- package/src/core/debug/matchers/IsNull.d.ts.map +1 -1
- package/src/core/debug/matchers/IsNull.js +2 -1
- package/src/core/debug/matchers/IsUndefined.d.ts +2 -1
- package/src/core/debug/matchers/IsUndefined.d.ts.map +1 -1
- package/src/core/debug/matchers/IsUndefined.js +2 -1
- package/src/core/events/signal/Signal.d.ts +15 -0
- package/src/core/events/signal/Signal.d.ts.map +1 -1
- package/src/core/events/signal/Signal.js +857 -820
- package/src/core/fsm/simple/SimpleStateMachineDescription.d.ts.map +1 -1
- package/src/core/fsm/simple/SimpleStateMachineDescription.js +4 -3
- package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_bruteforce.d.ts.map +1 -1
- package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_bruteforce.js +6 -1
- package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.d.ts +1 -1
- package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.d.ts.map +1 -1
- package/src/core/geom/2d/convex-hull/convex_hull_fixed_count_2d_relaxation.js +6 -7
- package/src/core/geom/2d/hash-grid/SpatialHashGrid.d.ts.map +1 -1
- package/src/core/geom/2d/hash-grid/SpatialHashGrid.js +23 -6
- package/src/core/geom/2d/line/ray2_ray2_compute_intersection_array_2d.d.ts.map +1 -1
- package/src/core/geom/2d/line/ray2_ray2_compute_intersection_array_2d.js +13 -1
- package/src/core/geom/3d/aabb/aabb3_raycast_hit_point.d.ts.map +1 -1
- package/src/core/geom/3d/aabb/aabb3_raycast_hit_point.js +53 -32
- package/src/core/geom/3d/atlas/segment/atlas_chart_growth_cost.d.ts +40 -0
- package/src/core/geom/3d/atlas/segment/atlas_chart_growth_cost.d.ts.map +1 -0
- package/src/core/geom/3d/atlas/segment/atlas_chart_growth_cost.js +54 -0
- package/src/core/geom/3d/atlas/segment/atlas_segment_charts.d.ts +21 -3
- package/src/core/geom/3d/atlas/segment/atlas_segment_charts.d.ts.map +1 -1
- package/src/core/geom/3d/atlas/segment/atlas_segment_charts.js +24 -15
- package/src/core/geom/3d/atlas/segment/atlas_segment_charts_atomic.d.ts +6 -3
- package/src/core/geom/3d/atlas/segment/atlas_segment_charts_atomic.d.ts.map +1 -1
- package/src/core/geom/3d/atlas/segment/atlas_segment_charts_atomic.js +9 -15
- package/src/core/geom/3d/cone/cone_compute_plane_side.d.ts.map +1 -1
- package/src/core/geom/3d/cone/cone_compute_plane_side.js +31 -19
- package/src/core/geom/3d/equirectangular/equirectangular_direction_to_uv.d.ts +11 -1
- package/src/core/geom/3d/equirectangular/equirectangular_direction_to_uv.d.ts.map +1 -1
- package/src/core/geom/3d/equirectangular/equirectangular_direction_to_uv.js +11 -1
- package/src/core/geom/3d/equirectangular/equirectangular_uv_to_direction.d.ts +11 -1
- package/src/core/geom/3d/equirectangular/equirectangular_uv_to_direction.d.ts.map +1 -1
- package/src/core/geom/3d/equirectangular/equirectangular_uv_to_direction.js +11 -1
- package/src/core/geom/3d/frustum/frustum3_compute_closest_point.d.ts.map +1 -1
- package/src/core/geom/3d/frustum/frustum3_compute_closest_point.js +55 -0
- package/src/core/geom/3d/frustum/frustum_from_projection_matrix_array.d.ts +14 -0
- package/src/core/geom/3d/frustum/frustum_from_projection_matrix_array.d.ts.map +1 -1
- package/src/core/geom/3d/frustum/frustum_from_projection_matrix_array.js +17 -1
- package/src/core/geom/3d/gjk/gjk.d.ts +15 -0
- package/src/core/geom/3d/gjk/gjk.d.ts.map +1 -1
- package/src/core/geom/3d/gjk/gjk.js +15 -0
- package/src/core/geom/3d/gjk/gjk_epa_penetration.d.ts.map +1 -1
- package/src/core/geom/3d/gjk/gjk_epa_penetration.js +18 -0
- package/src/core/geom/3d/hash-grid/PointHashGrid3.d.ts +32 -3
- package/src/core/geom/3d/hash-grid/PointHashGrid3.d.ts.map +1 -1
- package/src/core/geom/3d/hash-grid/PointHashGrid3.js +36 -3
- package/src/core/geom/3d/morton/v3_morton_encode_lut.d.ts.map +1 -1
- package/src/core/geom/3d/morton/v3_morton_encode_lut.js +11 -4
- package/src/core/geom/3d/morton/v3_morton_encode_normalized.d.ts +16 -4
- package/src/core/geom/3d/morton/v3_morton_encode_normalized.d.ts.map +1 -1
- package/src/core/geom/3d/morton/v3_morton_encode_normalized.js +21 -8
- package/src/core/geom/3d/normal/spherical/encode_unit_to_spheremap.d.ts.map +1 -1
- package/src/core/geom/3d/normal/spherical/encode_unit_to_spheremap.js +17 -3
- package/src/core/geom/3d/octahedra/octahedral_direction_to_uv.d.ts +10 -0
- package/src/core/geom/3d/octahedra/octahedral_direction_to_uv.d.ts.map +1 -1
- package/src/core/geom/3d/octahedra/octahedral_direction_to_uv.js +46 -49
- package/src/core/geom/3d/octahedra/octahedral_uv_to_direction.d.ts +13 -1
- package/src/core/geom/3d/octahedra/octahedral_uv_to_direction.d.ts.map +1 -1
- package/src/core/geom/3d/octahedra/octahedral_uv_to_direction.js +36 -39
- package/src/core/geom/3d/quadric/quadric3_to_tensor_m3_inverse.d.ts +4 -1
- package/src/core/geom/3d/quadric/quadric3_to_tensor_m3_inverse.d.ts.map +1 -1
- package/src/core/geom/3d/quadric/quadric3_to_tensor_m3_inverse.js +22 -4
- package/src/core/geom/3d/quaternion/quat3_canonicalize_sign_run.d.ts +38 -0
- package/src/core/geom/3d/quaternion/quat3_canonicalize_sign_run.d.ts.map +1 -0
- package/src/core/geom/3d/quaternion/quat3_canonicalize_sign_run.js +76 -0
- package/src/core/geom/3d/quaternion/quat3_encode_to_uint32.d.ts +11 -0
- package/src/core/geom/3d/quaternion/quat3_encode_to_uint32.d.ts.map +1 -1
- package/src/core/geom/3d/quaternion/quat3_encode_to_uint32.js +14 -34
- package/src/core/geom/3d/shape/PosedShape3D.d.ts +9 -0
- package/src/core/geom/3d/shape/PosedShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/PosedShape3D.js +43 -0
- package/src/core/geom/3d/shape/UnionShape3D.d.ts.map +1 -1
- package/src/core/geom/3d/shape/UnionShape3D.js +20 -3
- package/src/core/geom/3d/shape/json/type_adapters.d.ts +11 -2
- package/src/core/geom/3d/shape/json/type_adapters.d.ts.map +1 -1
- package/src/core/geom/3d/shape/json/type_adapters.js +36 -12
- package/src/core/geom/3d/sphere/harmonics/sh3_sample_irradiance_by_direction.d.ts +13 -0
- package/src/core/geom/3d/sphere/harmonics/sh3_sample_irradiance_by_direction.d.ts.map +1 -1
- package/src/core/geom/3d/sphere/harmonics/sh3_sample_irradiance_by_direction.js +17 -4
- package/src/core/geom/3d/tetrahedra/tetrahedral_flip_layouts.d.ts +88 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_flip_layouts.d.ts.map +1 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_flip_layouts.js +108 -0
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_23.d.ts.map +1 -1
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_23.js +13 -31
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_32.d.ts.map +1 -1
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_flip_32.js +14 -22
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.d.ts.map +1 -1
- package/src/core/geom/3d/tetrahedra/tetrahedral_mesh_improve_quality.js +96 -26
- package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.d.ts.map +1 -1
- package/src/core/geom/3d/tetrahedra/tetrahedron_contains_point.js +17 -6
- package/src/core/geom/3d/topology/struct/binary/io/bt_boundary_loop.d.ts +27 -0
- 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 +101 -0
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_close_boundary_holes.d.ts +3 -0
- 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 +5 -57
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_compute_vertex_quadrics.js +2 -34
- 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 +2 -43
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts +54 -33
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/bt_mesh_simplify.js +229 -68
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/edge/bt_edge_kill_parallels.js +4 -15
- package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_mesh_split_pinched_vertices.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_mesh_split_pinched_vertices.js +13 -1
- package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_fuse_duplicate_edges.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_fuse_duplicate_edges.js +3 -1
- package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/io/vertex/bt_vertex_replace.js +22 -3
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_count_faces.d.ts +17 -2
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_count_faces.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_count_faces.js +28 -4
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_get.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_edge_get.js +8 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_edge_adjacent_faces_weighted.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_face_get_edge_adjacent_faces_weighted.js +10 -2
- package/src/core/geom/3d/topology/struct/binary/query/bt_face_island_flood_fill.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_face_island_flood_fill.js +2 -0
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_distance_field.d.ts.map +1 -1
- package/src/core/geom/3d/topology/struct/binary/query/bt_mesh_build_boundary_distance_field.js +25 -5
- package/src/core/geom/3d/triangle/tri3_compute_normal.d.ts +5 -1
- package/src/core/geom/3d/triangle/tri3_compute_normal.d.ts.map +1 -1
- package/src/core/geom/3d/triangle/tri3_compute_normal.js +8 -1
- package/src/core/geom/3d/triangle/tri3_ray_intersection.d.ts.map +1 -1
- package/src/core/geom/3d/triangle/tri3_ray_intersection.js +15 -3
- package/src/core/geom/3d/triangle/tri3_ray_intersection_barycentric.d.ts +2 -1
- package/src/core/geom/3d/triangle/tri3_ray_intersection_barycentric.d.ts.map +1 -1
- package/src/core/geom/3d/triangle/tri3_ray_intersection_barycentric.js +2 -1
- package/src/core/geom/3d/triangle/tri3_ray_intersection_barycentric_edge.d.ts +1 -1
- package/src/core/geom/3d/triangle/tri3_ray_intersection_barycentric_edge.d.ts.map +1 -1
- package/src/core/geom/3d/triangle/tri3_ray_intersection_barycentric_edge.js +8 -1
- package/src/core/geom/vec/vector_normalize.d.ts.map +1 -1
- package/src/core/geom/vec/vector_normalize.js +5 -1
- package/src/core/geom/vec3/v3_slerp.d.ts.map +1 -1
- package/src/core/geom/vec3/v3_slerp.js +69 -4
- package/src/core/geom/vec4/v4_max_axis.d.ts +28 -0
- package/src/core/geom/vec4/v4_max_axis.d.ts.map +1 -0
- package/src/core/geom/vec4/v4_max_axis.js +41 -0
- package/src/core/graph/coloring/colorizeGraph.js +10 -7
- package/src/core/graph/layout/graph_peel_topological_layer.d.ts.map +1 -1
- package/src/core/graph/layout/graph_peel_topological_layer.js +16 -2
- package/src/core/json/JsonUtils.d.ts.map +1 -1
- package/src/core/json/JsonUtils.js +6 -2
- package/src/core/json/abstractJSONSerializer.d.ts.map +1 -1
- package/src/core/json/abstractJSONSerializer.js +5 -1
- package/src/core/lang/reactive/ReactiveOperatorType.d.ts +20 -0
- package/src/core/lang/reactive/ReactiveOperatorType.d.ts.map +1 -1
- package/src/core/lang/reactive/ReactiveOperatorType.js +34 -12
- package/src/core/localization/LanguageMetadata.d.ts +2 -1
- package/src/core/localization/LanguageMetadata.d.ts.map +1 -1
- package/src/core/localization/LanguageMetadata.js +6 -0
- package/src/core/localization/Localization.d.ts.map +1 -1
- package/src/core/localization/Localization.js +23 -10
- package/src/core/localization/LocalizationEngine.d.ts.map +1 -1
- package/src/core/localization/LocalizationEngine.js +4 -0
- package/src/core/math/fract.d.ts.map +1 -1
- package/src/core/math/fract.js +4 -3
- package/src/core/math/hash/squirrel3.d.ts +10 -2
- package/src/core/math/hash/squirrel3.d.ts.map +1 -1
- package/src/core/math/hash/squirrel3.js +16 -8
- package/src/core/math/linalg/m2/m2_polar_decomp_noS.d.ts +7 -0
- package/src/core/math/linalg/m2/m2_polar_decomp_noS.d.ts.map +1 -1
- package/src/core/math/linalg/m2/m2_polar_decomp_noS.js +20 -1
- package/src/core/math/physics/pdf/pdf_normal.d.ts +11 -3
- package/src/core/math/physics/pdf/pdf_normal.d.ts.map +1 -1
- package/src/core/math/physics/pdf/pdf_normal.js +25 -11
- package/src/core/math/solveQuadratic.d.ts.map +1 -1
- package/src/core/math/solveQuadratic.js +22 -3
- package/src/core/math/statistics/computeStatisticalPartialMedian.d.ts +9 -2
- package/src/core/math/statistics/computeStatisticalPartialMedian.d.ts.map +1 -1
- package/src/core/math/statistics/computeStatisticalPartialMedian.js +12 -6
- package/src/core/math/statistics/computeStatisticalPercentile.d.ts.map +1 -1
- package/src/core/math/statistics/computeStatisticalPercentile.js +9 -2
- package/src/core/math/statistics/gaussian_amplitude.d.ts +10 -1
- package/src/core/math/statistics/gaussian_amplitude.d.ts.map +1 -1
- package/src/core/math/statistics/gaussian_amplitude.js +20 -15
- package/src/core/model/BooleanVector3.d.ts.map +1 -1
- package/src/core/model/BooleanVector3.js +18 -2
- package/src/core/model/BoundedValue.d.ts +9 -0
- package/src/core/model/BoundedValue.d.ts.map +1 -1
- package/src/core/model/BoundedValue.js +30 -3
- package/src/core/model/ObservedBoolean.d.ts.map +1 -1
- package/src/core/model/ObservedBoolean.js +22 -2
- package/src/core/model/ObservedEnum.d.ts.map +1 -1
- package/src/core/model/ObservedEnum.js +6 -2
- package/src/core/model/node-graph/NodeGraph.d.ts +6 -1
- package/src/core/model/node-graph/NodeGraph.d.ts.map +1 -1
- package/src/core/model/node-graph/NodeGraph.js +22 -4
- package/src/core/model/node-graph/json/deserializeNodeGraphFromJSON.d.ts.map +1 -1
- package/src/core/model/node-graph/json/deserializeNodeGraphFromJSON.js +3 -1
- package/src/core/model/node-graph/json/serializeNodeGraphToJSON.d.ts.map +1 -1
- package/src/core/model/node-graph/json/serializeNodeGraphToJSON.js +5 -0
- package/src/core/model/node-graph/type/DataType.d.ts.map +1 -1
- package/src/core/model/node-graph/type/DataType.js +8 -0
- package/src/core/model/node-graph/type/ParametricDataType.d.ts.map +1 -1
- package/src/core/model/node-graph/type/ParametricDataType.js +19 -0
- package/src/core/model/node-graph/visual/NodeGraphVisualData.d.ts.map +1 -1
- package/src/core/model/node-graph/visual/NodeGraphVisualData.js +5 -0
- package/src/core/model/reactive/js/compileReactiveToJS.d.ts +22 -0
- package/src/core/model/reactive/js/compileReactiveToJS.d.ts.map +1 -1
- package/src/core/model/reactive/js/compileReactiveToJS.js +113 -219
- package/src/core/model/reactive/model/ReactiveBinaryExpression.d.ts.map +1 -1
- package/src/core/model/reactive/model/ReactiveBinaryExpression.js +8 -2
- package/src/core/model/reactive/model/comparative/ReactiveEquals.d.ts.map +1 -1
- package/src/core/model/reactive/model/comparative/ReactiveEquals.js +3 -1
- package/src/core/model/reactive/model/comparative/ReactiveNotEquals.d.ts.map +1 -1
- package/src/core/model/reactive/model/comparative/ReactiveNotEquals.js +2 -1
- package/src/core/model/reactive/model/terminal/ReactiveLiteralString.d.ts.map +1 -1
- package/src/core/model/reactive/model/terminal/ReactiveLiteralString.js +4 -2
- package/src/core/model/stat/Stat.d.ts.map +1 -1
- package/src/core/model/stat/Stat.js +4 -0
- package/src/core/parser/seedVariablesIntoTemplateString.d.ts.map +1 -1
- package/src/core/parser/seedVariablesIntoTemplateString.js +5 -0
- package/src/core/parser/simple/readArrayLiteral.d.ts.map +1 -1
- package/src/core/parser/simple/readArrayLiteral.js +7 -0
- package/src/core/parser/simple/readHexToken.d.ts +3 -0
- package/src/core/parser/simple/readHexToken.d.ts.map +1 -1
- package/src/core/parser/simple/readHexToken.js +39 -106
- package/src/core/parser/simple/readNumberToken.d.ts.map +1 -1
- package/src/core/parser/simple/readNumberToken.js +13 -4
- package/src/core/parser/simple/readUnsignedIntegerToken.d.ts +2 -0
- package/src/core/parser/simple/readUnsignedIntegerToken.d.ts.map +1 -1
- package/src/core/parser/simple/readUnsignedIntegerToken.js +31 -71
- package/src/core/parser/simple/read_digits.d.ts +31 -0
- package/src/core/parser/simple/read_digits.d.ts.map +1 -0
- package/src/core/parser/simple/read_digits.js +74 -0
- package/src/core/primitives/numbers/number_format_by_thousands.d.ts.map +1 -1
- package/src/core/primitives/numbers/number_format_by_thousands.js +16 -1
- package/src/core/primitives/numbers/number_pretty_print.d.ts.map +1 -1
- package/src/core/primitives/numbers/number_pretty_print.js +6 -1
- package/src/core/process/executor/ConcurrentExecutor.d.ts.map +1 -1
- package/src/core/process/executor/ConcurrentExecutor.js +36 -0
- package/src/core/process/task/Task.d.ts +8 -0
- package/src/core/process/task/Task.d.ts.map +1 -1
- package/src/core/process/task/Task.js +12 -1
- package/src/core/process/task/TaskGroup.d.ts +6 -0
- package/src/core/process/task/TaskGroup.d.ts.map +1 -1
- package/src/core/process/task/TaskGroup.js +7 -1
- package/src/core/process/undo/ActionProcessor.d.ts +12 -0
- package/src/core/process/undo/ActionProcessor.d.ts.map +1 -1
- package/src/core/process/undo/ActionProcessor.js +41 -15
- package/src/core/process/worker/OnDemandWorkerManager.d.ts.map +1 -1
- package/src/core/process/worker/OnDemandWorkerManager.js +6 -1
- package/src/core/process/worker/WorkerBuilder.d.ts.map +1 -1
- package/src/core/process/worker/WorkerBuilder.js +27 -5
- package/src/engine/Clock.d.ts.map +1 -1
- package/src/engine/Clock.js +11 -0
- package/src/engine/Engine.d.ts.map +1 -1
- package/src/engine/Engine.js +107 -6
- package/src/engine/achievements/AchievementManager.d.ts.map +1 -1
- package/src/engine/achievements/AchievementManager.js +16 -1
- package/src/engine/animation/clip/ecd_bind_animation_curve.d.ts.map +1 -1
- package/src/engine/animation/clip/ecd_bind_animation_curve.js +17 -6
- package/src/engine/animation/clip/hemisphere_align_quaternion_values.d.ts +19 -10
- package/src/engine/animation/clip/hemisphere_align_quaternion_values.d.ts.map +1 -1
- package/src/engine/animation/clip/hemisphere_align_quaternion_values.js +19 -23
- package/src/engine/animation/keyed2/AnimationTrackPlayback.d.ts +1 -1
- package/src/engine/animation/keyed2/AnimationTrackPlayback.d.ts.map +1 -1
- package/src/engine/animation/keyed2/AnimationTrackPlayback.js +21 -4
- package/src/engine/asset/AssetManager.d.ts.map +1 -1
- package/src/engine/asset/AssetManager.js +11 -3
- package/src/engine/control/first-person/FirstPersonPlayerController.d.ts +1 -0
- package/src/engine/control/first-person/FirstPersonPlayerController.d.ts.map +1 -1
- package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts +28 -0
- package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.d.ts.map +1 -1
- package/src/engine/control/first-person/FirstPersonPlayerControllerConfig.js +14 -0
- package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts +23 -2
- package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.d.ts.map +1 -1
- package/src/engine/control/first-person/FirstPersonPlayerControllerSystem.js +2122 -2078
- package/src/engine/ecs/Entity.d.ts.map +1 -1
- package/src/engine/ecs/Entity.js +43 -7
- package/src/engine/ecs/EntityBlueprint.d.ts.map +1 -1
- package/src/engine/ecs/EntityBlueprint.js +13 -4
- package/src/engine/ecs/EntityComponentDataset.d.ts.map +1 -1
- package/src/engine/ecs/EntityComponentDataset.js +95 -9
- package/src/engine/ecs/EntityManager.d.ts +16 -0
- package/src/engine/ecs/EntityManager.d.ts.map +1 -1
- package/src/engine/ecs/EntityManager.js +112 -37
- package/src/engine/ecs/EntityObserver.d.ts +7 -0
- package/src/engine/ecs/EntityObserver.d.ts.map +1 -1
- package/src/engine/ecs/EntityObserver.js +8 -1
- package/src/engine/ecs/System.d.ts +23 -0
- package/src/engine/ecs/System.d.ts.map +1 -1
- package/src/engine/ecs/System.js +25 -0
- package/src/engine/ecs/components/Tag.d.ts.map +1 -1
- package/src/engine/ecs/components/Tag.js +4 -1
- package/src/engine/ecs/computeComponentClassName.d.ts +13 -1
- package/src/engine/ecs/computeComponentClassName.d.ts.map +1 -1
- package/src/engine/ecs/computeComponentClassName.js +11 -1
- package/src/engine/ecs/dynamic_actions/DynamicActorSystem.d.ts.map +1 -1
- package/src/engine/ecs/dynamic_actions/DynamicActorSystem.js +11 -0
- package/src/engine/ecs/fow/FogOfWar.d.ts.map +1 -1
- package/src/engine/ecs/fow/FogOfWar.js +37 -11
- package/src/engine/ecs/parent/EntityNode.d.ts.map +1 -1
- package/src/engine/ecs/parent/EntityNode.js +8 -0
- package/src/engine/ecs/speaker/VoiceSystem.d.ts.map +1 -1
- package/src/engine/ecs/speaker/VoiceSystem.js +9 -0
- package/src/engine/ecs/storage/binary/BinaryClassSerializationAdapter.d.ts +15 -0
- package/src/engine/ecs/storage/binary/BinaryClassSerializationAdapter.d.ts.map +1 -1
- package/src/engine/ecs/storage/binary/BinaryClassSerializationAdapter.js +18 -0
- package/src/engine/ecs/system/AbstractContextSystem.d.ts.map +1 -1
- package/src/engine/ecs/system/AbstractContextSystem.js +14 -4
- package/src/engine/ecs/system/SystemEntityContext.d.ts +12 -0
- package/src/engine/ecs/system/SystemEntityContext.d.ts.map +1 -1
- package/src/engine/ecs/system/SystemEntityContext.js +23 -0
- package/src/engine/ecs/system_validate_class.d.ts.map +1 -1
- package/src/engine/ecs/system_validate_class.js +6 -2
- package/src/engine/ecs/terrain/ecs/cling/ClingToTerrainSystem.js +37 -8
- package/src/engine/ecs/terrain/tiles/TerrainTile.d.ts.map +1 -1
- package/src/engine/ecs/terrain/tiles/TerrainTile.js +45 -3
- package/src/engine/ecs/terrain/tiles/TerrainTileManager.d.ts.map +1 -1
- package/src/engine/ecs/terrain/tiles/TerrainTileManager.js +5 -8
- package/src/engine/graphics/ecs/camera/pp/PerfectPanner.d.ts.map +1 -1
- package/src/engine/graphics/ecs/camera/pp/PerfectPanner.js +62 -7
- package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMesh.d.ts +9 -0
- package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMesh.d.ts.map +1 -1
- package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMesh.js +13 -0
- package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshAnimationControllerSystem.d.ts +11 -0
- package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshAnimationControllerSystem.d.ts.map +1 -1
- package/src/engine/graphics/ecs/mesh-v2/aggregate/SGMeshAnimationControllerSystem.js +78 -13
- package/src/engine/graphics/ecs/path/tube/build/make_ring_vertices.d.ts.map +1 -1
- package/src/engine/graphics/ecs/path/tube/build/make_ring_vertices.js +22 -8
- package/src/engine/graphics/geometry/buffered/geometry_compute_vertex_normals_indexed.d.ts.map +1 -1
- package/src/engine/graphics/geometry/buffered/geometry_compute_vertex_normals_indexed.js +18 -2
- package/src/engine/graphics/geometry/geometry_construct_triangle_normal.d.ts +3 -1
- package/src/engine/graphics/geometry/geometry_construct_triangle_normal.d.ts.map +1 -1
- package/src/engine/graphics/geometry/geometry_construct_triangle_normal.js +3 -1
- package/src/engine/graphics/geometry/geometry_construct_triangle_normal_area_weighted.d.ts +32 -0
- package/src/engine/graphics/geometry/geometry_construct_triangle_normal_area_weighted.d.ts.map +1 -0
- package/src/engine/graphics/geometry/geometry_construct_triangle_normal_area_weighted.js +53 -0
- package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts +22 -2
- package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.d.ts.map +1 -1
- package/src/engine/graphics/particles/particular/engine/emitter/ParticleEmitter.js +1201 -1160
- package/src/engine/graphics/particles/particular/engine/simulator/SimulationStepCurlNoiseVelocity.d.ts +0 -1
- package/src/engine/graphics/particles/particular/engine/simulator/SimulationStepCurlNoiseVelocity.d.ts.map +1 -1
- package/src/engine/graphics/particles/particular/engine/simulator/SimulationStepCurlNoiseVelocity.js +10 -5
- package/src/engine/graphics/particles/particular/engine/simulator/update_parameters.d.ts.map +1 -1
- package/src/engine/graphics/particles/particular/engine/simulator/update_parameters.js +23 -0
- package/src/engine/graphics/particles/particular/group/itemSizeFromAttributeType.d.ts +1 -1
- package/src/engine/graphics/sh3/path_tracer/texture/apply_texture_clamping_to_coordinate.d.ts.map +1 -1
- package/src/engine/graphics/sh3/path_tracer/texture/apply_texture_clamping_to_coordinate.js +6 -1
- package/src/engine/graphics/texture/atlas/ManagedTextureAtlas.d.ts.map +1 -1
- package/src/engine/graphics/texture/atlas/ManagedTextureAtlas.js +20 -0
- package/src/engine/graphics/texture/atlas/TextureAtlas.d.ts +1 -0
- package/src/engine/graphics/texture/atlas/TextureAtlas.d.ts.map +1 -1
- package/src/engine/graphics/texture/atlas/TextureAtlas.js +24 -5
- package/src/engine/graphics/texture/sampler/Sampler2D.d.ts.map +1 -1
- package/src/engine/graphics/texture/sampler/Sampler2D.js +14 -1
- package/src/engine/graphics/texture/sampler/sampler2d_sub_copy_same_item_size.d.ts.map +1 -1
- package/src/engine/graphics/texture/sampler/sampler2d_sub_copy_same_item_size.js +16 -5
- package/src/engine/graphics/texture/sampler/sampler2d_to_uint8_RGBA.d.ts.map +1 -1
- package/src/engine/graphics/texture/sampler/sampler2d_to_uint8_RGBA.js +29 -8
- package/src/engine/graphics/texture/sampler/serialization/TextureBinaryBufferSerializer.d.ts.map +1 -1
- package/src/engine/graphics/texture/sampler/serialization/TextureBinaryBufferSerializer.js +8 -3
- package/src/engine/graphics3/DecalSystem.d.ts +5 -4
- package/src/engine/graphics3/DecalSystem.d.ts.map +1 -1
- package/src/engine/graphics3/DecalSystem.js +5 -4
- package/src/engine/graphics3/GraphicsEngine.d.ts +40 -7
- package/src/engine/graphics3/GraphicsEngine.d.ts.map +1 -1
- package/src/engine/graphics3/GraphicsEngine.js +92 -7
- package/src/engine/graphics3/MeshSystem.d.ts +7 -0
- package/src/engine/graphics3/MeshSystem.d.ts.map +1 -1
- package/src/engine/graphics3/MeshSystem.js +681 -661
- package/src/engine/graphics3/ParticleEmitterSystem.d.ts +1 -0
- package/src/engine/graphics3/ParticleEmitterSystem.d.ts.map +1 -1
- package/src/engine/graphics3/ParticleEmitterSystem.js +1 -0
- package/src/engine/graphics3/TerrainSystem.d.ts +10 -40
- package/src/engine/graphics3/TerrainSystem.d.ts.map +1 -1
- package/src/engine/graphics3/TerrainSystem.js +186 -185
- package/src/engine/graphics3/Trail3DSystem.d.ts +28 -19
- package/src/engine/graphics3/Trail3DSystem.d.ts.map +1 -1
- package/src/engine/graphics3/Trail3DSystem.js +57 -64
- package/src/engine/graphics3/debug/gizmo_write_geometry.d.ts.map +1 -1
- package/src/engine/graphics3/debug/gizmo_write_geometry.js +7 -59
- package/src/engine/graphics3/decal/GPUDecalRenderer.d.ts.map +1 -1
- package/src/engine/graphics3/decal/GPUDecalRenderer.js +23 -7
- package/src/engine/graphics3/decal/shader_cluster_assign_decals.d.ts.map +1 -1
- package/src/engine/graphics3/decal/shader_cluster_assign_decals.js +29 -6
- package/src/engine/graphics3/path/tube_stream_write_geometry.d.ts.map +1 -1
- package/src/engine/graphics3/path/tube_stream_write_geometry.js +7 -56
- package/src/engine/graphics3/register_instance_animation.d.ts +3 -3
- package/src/engine/graphics3/register_instance_animation.js +3 -3
- package/src/engine/graphics3/terrain/GPUTerrainSplatRenderer.d.ts.map +1 -1
- package/src/engine/graphics3/terrain/TERRAIN_MATERIAL_TEMPLATE.d.ts +77 -0
- package/src/engine/graphics3/terrain/TERRAIN_MATERIAL_TEMPLATE.d.ts.map +1 -0
- package/src/engine/graphics3/terrain/TERRAIN_MATERIAL_TEMPLATE.js +485 -0
- package/src/engine/graphics3/terrain/TerrainShadeMaterial.d.ts +103 -0
- package/src/engine/graphics3/terrain/TerrainShadeMaterial.d.ts.map +1 -0
- package/src/engine/graphics3/terrain/TerrainShadeMaterial.js +130 -0
- package/src/engine/graphics3/terrain/chunk_terrain_material_surface.d.ts +23 -0
- package/src/engine/graphics3/terrain/chunk_terrain_material_surface.d.ts.map +1 -0
- package/src/engine/graphics3/terrain/chunk_terrain_material_surface.js +68 -0
- package/src/engine/graphics3/trail/trail_tube_write_geometry.d.ts.map +1 -1
- package/src/engine/graphics3/trail/trail_tube_write_geometry.js +8 -59
- package/src/engine/grid/transform2grid/Transform2GridPositionSystem.d.ts.map +1 -1
- package/src/engine/grid/transform2grid/Transform2GridPositionSystem.js +10 -0
- package/src/engine/input/devices/PointerDevice.d.ts.map +1 -1
- package/src/engine/input/devices/PointerDevice.js +58 -5
- package/src/engine/input/ecs/ism/InputMapProgram.d.ts.map +1 -1
- package/src/engine/input/ecs/ism/InputMapProgram.js +13 -0
- package/src/engine/input/ecs/systems/InputControllerSystem.d.ts +1 -0
- package/src/engine/input/ecs/systems/InputControllerSystem.d.ts.map +1 -1
- package/src/engine/input/ecs/systems/InputControllerSystem.js +52 -2
- package/src/engine/intelligence/behavior/composite/ParallelBehavior.d.ts.map +1 -1
- package/src/engine/intelligence/behavior/composite/ParallelBehavior.js +8 -0
- package/src/engine/intelligence/behavior/decorator/RepeatBehavior.d.ts.map +1 -1
- package/src/engine/intelligence/behavior/decorator/RepeatBehavior.js +7 -0
- package/src/engine/intelligence/behavior/decorator/RepeatUntilSuccessBehavior.d.ts.map +1 -1
- package/src/engine/intelligence/behavior/decorator/RepeatUntilSuccessBehavior.js +14 -0
- package/src/engine/intelligence/behavior/ecs/BehaviorSystem.d.ts.map +1 -1
- package/src/engine/intelligence/behavior/ecs/BehaviorSystem.js +13 -0
- package/src/engine/interpolation/InterpolationLog.d.ts +51 -4
- package/src/engine/interpolation/InterpolationLog.d.ts.map +1 -1
- package/src/engine/interpolation/InterpolationLog.js +132 -2
- package/src/engine/interpolation/InterpolationSystem.d.ts +113 -35
- package/src/engine/interpolation/InterpolationSystem.d.ts.map +1 -1
- package/src/engine/interpolation/InterpolationSystem.js +674 -50
- package/src/engine/network/NetworkSession.d.ts +176 -47
- package/src/engine/network/NetworkSession.d.ts.map +1 -1
- package/src/engine/network/NetworkSession.js +1462 -272
- package/src/engine/network/README.md +106 -3
- package/src/engine/network/SMOOTHNESS_DESIGN.md +392 -0
- package/src/engine/network/adapters/PoseCorrection.d.ts +50 -0
- package/src/engine/network/adapters/PoseCorrection.d.ts.map +1 -0
- package/src/engine/network/adapters/PoseCorrection.js +211 -0
- package/src/engine/network/adapters/TransformReplicationAdapter.d.ts +1 -0
- package/src/engine/network/adapters/TransformReplicationAdapter.d.ts.map +1 -1
- package/src/engine/network/adapters/TransformReplicationAdapter.js +17 -0
- package/src/engine/network/adapters/VelocityCorrection.d.ts +31 -0
- package/src/engine/network/adapters/VelocityCorrection.d.ts.map +1 -0
- package/src/engine/network/adapters/VelocityCorrection.js +71 -0
- package/src/engine/network/adapters/replicate_transform64.d.ts +13 -0
- package/src/engine/network/adapters/replicate_transform64.d.ts.map +1 -0
- package/src/engine/network/adapters/replicate_transform64.js +18 -0
- package/src/engine/network/adapters/rigid_body_of.d.ts +22 -0
- package/src/engine/network/adapters/rigid_body_of.d.ts.map +1 -0
- package/src/engine/network/adapters/rigid_body_of.js +33 -0
- package/src/engine/network/correction/Correction.d.ts +120 -0
- package/src/engine/network/correction/Correction.d.ts.map +1 -0
- package/src/engine/network/correction/Correction.js +143 -0
- package/src/engine/network/ecs/NetworkSystem.d.ts +36 -7
- package/src/engine/network/ecs/NetworkSystem.d.ts.map +1 -1
- package/src/engine/network/ecs/NetworkSystem.js +49 -7
- package/src/engine/network/orchestrator/NetworkPeer.d.ts +50 -1
- package/src/engine/network/orchestrator/NetworkPeer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/NetworkPeer.js +143 -10
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts +38 -2
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.d.ts.map +1 -1
- package/src/engine/network/orchestrator/ServerAuthoritativeClient.js +58 -10
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts +68 -2
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.d.ts.map +1 -1
- package/src/engine/network/orchestrator/ServerAuthoritativeServer.js +299 -18
- package/src/engine/network/replication/Replicator.d.ts +8 -1
- package/src/engine/network/replication/Replicator.d.ts.map +1 -1
- package/src/engine/network/replication/Replicator.js +50 -6
- package/src/engine/network/sim/ActionLog.d.ts +5 -2
- package/src/engine/network/sim/ActionLog.d.ts.map +1 -1
- package/src/engine/network/sim/ActionLog.js +5 -2
- package/src/engine/network/sim/RewindEngine.d.ts.map +1 -1
- package/src/engine/network/sim/RewindEngine.js +6 -0
- package/src/engine/network/sim/SimActionExecutor.d.ts +48 -3
- package/src/engine/network/sim/SimActionExecutor.d.ts.map +1 -1
- package/src/engine/network/sim/SimActionExecutor.js +152 -6
- package/src/engine/network/sim/SmoothingState.d.ts +54 -2
- package/src/engine/network/sim/SmoothingState.d.ts.map +1 -1
- package/src/engine/network/sim/SmoothingState.js +107 -3
- package/src/engine/network/state/MutationLedger.d.ts.map +1 -1
- package/src/engine/network/state/MutationLedger.js +18 -2
- package/src/engine/network/state/PredictionHistory.d.ts +67 -0
- package/src/engine/network/state/PredictionHistory.d.ts.map +1 -0
- package/src/engine/network/state/PredictionHistory.js +145 -0
- package/src/engine/network/time/RenderPlayout.d.ts +2 -1
- package/src/engine/network/time/RenderPlayout.d.ts.map +1 -1
- package/src/engine/network/time/RenderPlayout.js +174 -163
- package/src/engine/network/transport/DeferredTransport.d.ts +57 -0
- package/src/engine/network/transport/DeferredTransport.d.ts.map +1 -0
- package/src/engine/network/transport/DeferredTransport.js +143 -0
- package/src/engine/network/transport/LoopbackTransport.d.ts +8 -0
- package/src/engine/network/transport/LoopbackTransport.d.ts.map +1 -1
- package/src/engine/network/transport/LoopbackTransport.js +12 -1
- package/src/engine/network/transport/ReliableCommandPipeline.d.ts.map +1 -1
- package/src/engine/network/transport/ReliableCommandPipeline.js +20 -0
- package/src/engine/network/transport/adapters/NodeUDPTransport.d.ts.map +1 -1
- package/src/engine/network/transport/adapters/NodeUDPTransport.js +11 -2
- package/src/engine/network/transport/adapters/WebTransportTransport.d.ts.map +1 -1
- package/src/engine/network/transport/adapters/WebTransportTransport.js +8 -1
- package/src/engine/network/transport/fragments/FragmentAssembler.d.ts +2 -1
- package/src/engine/network/transport/fragments/FragmentAssembler.d.ts.map +1 -1
- package/src/engine/network/transport/fragments/FragmentAssembler.js +67 -3
- package/src/engine/network/transport/fragments/fragment_send.d.ts +8 -0
- package/src/engine/network/transport/fragments/fragment_send.d.ts.map +1 -1
- package/src/engine/network/transport/fragments/fragment_send.js +17 -7
- package/src/engine/network/transport/fragments/packet_size.d.ts +6 -0
- package/src/engine/network/transport/fragments/packet_size.d.ts.map +1 -1
- package/src/engine/network/transport/fragments/packet_size.js +6 -0
- package/src/engine/physics/ccd/linear_sweep.d.ts.map +1 -1
- package/src/engine/physics/ccd/linear_sweep.js +19 -1
- package/src/engine/physics/cloth/ecs/ClothWorld.d.ts +7 -3
- package/src/engine/physics/cloth/ecs/ClothWorld.d.ts.map +1 -1
- package/src/engine/physics/cloth/ecs/ClothWorld.js +34 -4
- package/src/engine/physics/cloth/solver/cloth_self_find.js +17 -0
- package/src/engine/physics/contact/ManifoldStore.d.ts +20 -1
- package/src/engine/physics/contact/ManifoldStore.d.ts.map +1 -1
- package/src/engine/physics/contact/ManifoldStore.js +24 -2
- package/src/engine/physics/ecs/PhysicsSystem.d.ts +51 -88
- package/src/engine/physics/ecs/PhysicsSystem.d.ts.map +1 -1
- package/src/engine/physics/ecs/PhysicsSystem.js +82 -217
- package/src/engine/physics/ecs/is_sensor.d.ts +24 -0
- package/src/engine/physics/ecs/is_sensor.d.ts.map +1 -1
- package/src/engine/physics/ecs/is_sensor.js +39 -0
- package/src/engine/physics/fluid/ecs/FluidComponent.d.ts +18 -4
- package/src/engine/physics/fluid/ecs/FluidComponent.d.ts.map +1 -1
- package/src/engine/physics/fluid/ecs/FluidComponent.js +29 -8
- package/src/engine/physics/fluid/ecs/FluidObstacleSystem.d.ts +4 -4
- package/src/engine/physics/fluid/effector/AbstractFluidEffector.d.ts +8 -0
- package/src/engine/physics/fluid/effector/AbstractFluidEffector.d.ts.map +1 -1
- package/src/engine/physics/fluid/effector/AbstractFluidEffector.js +8 -0
- package/src/engine/physics/fluid/solver/NOTES.md +46 -0
- package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_scalar.js +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_advect_maccormack_velocity.js +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_advect_sl_velocity.js +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_apply_advection_forward.js +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_apply_scalar_advection.js +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_apply_vorticity_confinement.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_apply_vorticity_confinement.js +8 -0
- package/src/engine/physics/fluid/solver/v3_grid_compute_divergence.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_compute_divergence.js +8 -0
- package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_grid_subtract_pressure_gradient.js +8 -0
- package/src/engine/physics/fluid/solver/v3_mac_advect_scalar.d.ts +5 -0
- package/src/engine/physics/fluid/solver/v3_mac_advect_scalar.d.ts.map +1 -1
- package/src/engine/physics/fluid/solver/v3_mac_advect_scalar.js +5 -0
- package/src/engine/physics/integration/integrate_velocity.d.ts +15 -0
- package/src/engine/physics/integration/integrate_velocity.d.ts.map +1 -1
- package/src/engine/physics/integration/integrate_velocity.js +15 -0
- package/src/engine/physics/island/IslandBuilder.d.ts.map +1 -1
- package/src/engine/physics/island/IslandBuilder.js +6 -7
- package/src/engine/physics/mls-mpm/MLS_MPM.d.ts.map +1 -1
- package/src/engine/physics/mls-mpm/MLS_MPM.js +29 -13
- package/src/engine/physics/mls-mpm/mls_mpm_demo_scene.d.ts +29 -0
- package/src/engine/physics/mls-mpm/mls_mpm_demo_scene.d.ts.map +1 -0
- package/src/engine/physics/mls-mpm/mls_mpm_demo_scene.js +44 -0
- package/src/engine/physics/mls-mpm/testMLS_MPM.js +3 -3
- package/src/engine/physics/narrowphase/narrowphase_step.d.ts.map +1 -1
- package/src/engine/physics/narrowphase/narrowphase_step.js +74 -11
- package/src/engine/physics/queries/overlap_shape.d.ts.map +1 -1
- package/src/engine/physics/queries/overlap_shape.js +92 -45
- package/src/engine/physics/queries/raycast.d.ts.map +1 -1
- package/src/engine/physics/queries/raycast.js +55 -43
- package/src/engine/physics/queries/shape_cast.d.ts.map +1 -1
- package/src/engine/physics/queries/shape_cast.js +185 -174
- package/src/engine/physics/solver/solve_contacts.d.ts.map +1 -1
- package/src/engine/physics/solver/solve_contacts.js +42 -19
- package/src/engine/plugin/EnginePluginManager.d.ts +10 -0
- package/src/engine/plugin/EnginePluginManager.d.ts.map +1 -1
- package/src/engine/plugin/EnginePluginManager.js +54 -1
- package/src/engine/plugin/PluginReferenceContext.d.ts.map +1 -1
- package/src/engine/plugin/PluginReferenceContext.js +7 -3
- package/src/engine/reference/v2/Reference.d.ts +9 -0
- package/src/engine/reference/v2/Reference.d.ts.map +1 -1
- package/src/engine/reference/v2/Reference.js +39 -2
- package/src/engine/simulation/Ticker.d.ts.map +1 -1
- package/src/engine/simulation/Ticker.js +20 -1
- package/src/engine/sound/ecs/SoundListenerSystem.d.ts +27 -0
- package/src/engine/sound/ecs/SoundListenerSystem.d.ts.map +1 -1
- package/src/engine/sound/ecs/SoundListenerSystem.js +82 -21
- package/src/engine/sound/ecs/audio/LiveEmitterSet.d.ts.map +1 -1
- package/src/engine/sound/ecs/audio/LiveEmitterSet.js +394 -356
- package/src/engine/sound/material/concrete/SoundMaterialComposition.d.ts.map +1 -1
- package/src/engine/sound/material/concrete/SoundMaterialComposition.js +54 -17
- package/src/engine/sound/material/detector/terrain/TerrainSoundMaterialSurfaceDetector.d.ts.map +1 -1
- package/src/engine/sound/material/detector/terrain/TerrainSoundMaterialSurfaceDetector.js +34 -3
- package/src/engine/sound/simulation/core/AcousticSolution.d.ts +5 -0
- package/src/engine/sound/simulation/core/AcousticSolution.d.ts.map +1 -1
- package/src/engine/sound/simulation/core/AcousticSolution.js +5 -0
- package/src/engine/sound/simulation/definition/AcousticMaterial.d.ts +8 -0
- package/src/engine/sound/simulation/definition/AcousticMaterial.d.ts.map +1 -1
- package/src/engine/sound/simulation/definition/AcousticMaterial.js +8 -0
- package/src/engine/sound/simulation/probe/probe_visibility_augment.d.ts +6 -4
- package/src/engine/sound/simulation/probe/probe_visibility_augment.d.ts.map +1 -1
- package/src/engine/sound/simulation/probe/probe_visibility_augment.js +19 -7
- package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.d.ts +39 -0
- package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.d.ts.map +1 -1
- package/src/engine/sound/simulation/render/FoaProbeReverbRenderer.js +130 -1
- package/src/engine/sound/simulation/render/ProbeReverbRenderer.d.ts +3 -2
- package/src/engine/sound/simulation/render/ProbeReverbRenderer.d.ts.map +1 -1
- package/src/engine/sound/simulation/render/ProbeReverbRenderer.js +15 -1
- package/src/engine/sound/sopra/SopraEngine.d.ts +10 -0
- package/src/engine/sound/sopra/SopraEngine.d.ts.map +1 -1
- package/src/engine/sound/sopra/SopraEngine.js +486 -440
- package/src/engine/sound/sopra/runtime/BusGraph.d.ts +29 -0
- package/src/engine/sound/sopra/runtime/BusGraph.d.ts.map +1 -1
- package/src/engine/sound/sopra/runtime/BusGraph.js +69 -2
- package/src/engine/sound/sopra/runtime/EventInstance.d.ts.map +1 -1
- package/src/engine/sound/sopra/runtime/EventInstance.js +130 -9
- package/src/engine/ui/GUIEngine.d.ts +14 -0
- package/src/engine/ui/GUIEngine.d.ts.map +1 -1
- package/src/engine/ui/GUIEngine.js +52 -4
- package/src/format/image/avif/api/apply_transformations.d.ts +2 -1
- package/src/format/image/avif/api/apply_transformations.d.ts.map +1 -1
- package/src/format/image/avif/api/apply_transformations.js +129 -120
- package/src/format/image/avif/api/convert_to_rgba.d.ts.map +1 -1
- package/src/format/image/avif/api/convert_to_rgba.js +35 -2
- package/src/format/image/avif/api/decode_image_item.d.ts +2 -1
- package/src/format/image/avif/api/decode_image_item.d.ts.map +1 -1
- package/src/format/image/avif/api/decode_image_item.js +322 -234
- package/src/format/image/avif/av1/decode/decode_av1_still.js +329 -309
- package/src/format/image/avif/av1/encode/encode_tile.js +2349 -2331
- package/src/format/image/avif/av1/entropy/symbol_cost.d.ts.map +1 -1
- package/src/format/image/avif/av1/entropy/symbol_cost.js +86 -76
- package/src/format/image/avif/heif/AvifFile.d.ts +11 -0
- package/src/format/image/avif/heif/AvifFile.d.ts.map +1 -1
- package/src/format/image/avif/heif/AvifFile.js +154 -142
- package/src/format/image/avif/heif/find_item_properties.d.ts +23 -0
- package/src/format/image/avif/heif/find_item_properties.d.ts.map +1 -0
- package/src/format/image/avif/heif/find_item_properties.js +36 -0
- package/src/format/image/avif/heif/parse_avif_file.js +6 -3
- package/src/format/image/avif/heif/read_item_data.d.ts.map +1 -1
- package/src/format/image/avif/heif/read_item_data.js +131 -97
- package/src/format/image/jpeg/decodeScan.d.ts.map +1 -1
- package/src/format/image/jpeg/decodeScan.js +17 -0
- package/src/format/scene/gltf/gltf_parse_container.d.ts.map +1 -1
- package/src/format/scene/gltf/gltf_parse_container.js +61 -41
- package/src/format/scene/gltf/gltf_read_accessor.d.ts +21 -0
- package/src/format/scene/gltf/gltf_read_accessor.d.ts.map +1 -1
- package/src/format/scene/gltf/gltf_read_accessor.js +37 -0
- package/src/format/scene/usd/usd_compose_transform.d.ts.map +1 -1
- package/src/format/scene/usd/usd_compose_transform.js +56 -6
- package/src/format/texture/basis/transcode/fit_endpoints.d.ts +6 -0
- package/src/format/texture/basis/transcode/fit_endpoints.d.ts.map +1 -1
- package/src/format/texture/basis/transcode/fit_endpoints.js +33 -39
- package/src/generation/filtering/numeric/CellFilterCache.d.ts +17 -0
- package/src/generation/filtering/numeric/CellFilterCache.d.ts.map +1 -1
- package/src/generation/filtering/numeric/CellFilterCache.js +36 -3
- package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainObstacle.d.ts +9 -0
- package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainObstacle.d.ts.map +1 -1
- package/src/generation/grid/actions/ContinuousGridCellActionSetTerrainObstacle.js +37 -6
- package/src/generation/grid/actions/ContinuousGridCellActionWriteObstacle.d.ts.map +1 -1
- package/src/generation/grid/actions/ContinuousGridCellActionWriteObstacle.js +8 -21
- package/src/generation/grid/actions/grid_obstacle_write_grid_point.d.ts +28 -0
- package/src/generation/grid/actions/grid_obstacle_write_grid_point.d.ts.map +1 -0
- package/src/generation/grid/actions/grid_obstacle_write_grid_point.js +41 -0
- package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.d.ts +15 -1
- package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.d.ts.map +1 -1
- package/src/generation/grid/generation/GridTaskDensityMarkerDistribution.js +17 -3
- package/src/generation/markers/actions/MarkerNodeProcessingRuleSet.d.ts.map +1 -1
- package/src/generation/markers/actions/MarkerNodeProcessingRuleSet.js +16 -1
- package/src/generation/placement/action/GridCellActionWriteFilterToLayer.d.ts.map +1 -1
- package/src/generation/placement/action/GridCellActionWriteFilterToLayer.js +8 -1
- package/src/generation/theme/TerrainTheme.d.ts.map +1 -1
- package/src/generation/theme/TerrainTheme.js +20 -1
- package/src/shade/RENDERER_CONTRACT.md +48 -6
- package/src/shade/descriptor/texture/format/gpu_texture_formats_copy_compatible.d.ts +23 -0
- package/src/shade/descriptor/texture/format/gpu_texture_formats_copy_compatible.d.ts.map +1 -0
- package/src/shade/descriptor/texture/format/gpu_texture_formats_copy_compatible.js +28 -0
- package/src/shade/descriptor/texture/format/gpu_texture_formats_view_compatible.d.ts +25 -0
- package/src/shade/descriptor/texture/format/gpu_texture_formats_view_compatible.d.ts.map +1 -0
- package/src/shade/descriptor/texture/format/gpu_texture_formats_view_compatible.js +42 -0
- package/src/shade/device/ShadeGPUCommandContext.d.ts.map +1 -1
- package/src/shade/device/ShadeGPUCommandContext.js +874 -857
- package/src/shade/device/mock/SoftwareGPUBindGroup.d.ts +38 -1
- package/src/shade/device/mock/SoftwareGPUBindGroup.d.ts.map +1 -1
- package/src/shade/device/mock/SoftwareGPUBindGroup.js +73 -1
- package/src/shade/device/mock/SoftwareGPUBuffer.d.ts.map +1 -1
- package/src/shade/device/mock/SoftwareGPUBuffer.js +5 -0
- package/src/shade/device/mock/SoftwareGPUCommandBuffer.d.ts +34 -0
- package/src/shade/device/mock/SoftwareGPUCommandBuffer.d.ts.map +1 -1
- package/src/shade/device/mock/SoftwareGPUCommandBuffer.js +71 -1
- package/src/shade/device/mock/SoftwareGPUCommandEncoder.d.ts +15 -0
- package/src/shade/device/mock/SoftwareGPUCommandEncoder.d.ts.map +1 -1
- package/src/shade/device/mock/SoftwareGPUCommandEncoder.js +109 -1
- package/src/shade/device/mock/SoftwareGPUComputePassEncoder.d.ts.map +1 -1
- package/src/shade/device/mock/SoftwareGPUComputePassEncoder.js +51 -0
- package/src/shade/device/mock/SoftwareGPUDevice.d.ts +5 -1
- package/src/shade/device/mock/SoftwareGPUDevice.d.ts.map +1 -1
- package/src/shade/device/mock/SoftwareGPUDevice.js +58 -1
- package/src/shade/device/mock/SoftwareGPUPipeline.d.ts +1 -0
- package/src/shade/device/mock/SoftwareGPUPipeline.d.ts.map +1 -1
- package/src/shade/device/mock/SoftwareGPUPipeline.js +17 -11
- package/src/shade/device/mock/SoftwareGPUQueue.d.ts.map +1 -1
- package/src/shade/device/mock/SoftwareGPUQueue.js +41 -0
- package/src/shade/device/mock/SoftwareGPURenderPassEncoder.d.ts.map +1 -1
- package/src/shade/device/mock/SoftwareGPURenderPassEncoder.js +24 -0
- package/src/shade/device/mock/SoftwareGPUTexture.d.ts +11 -1
- package/src/shade/device/mock/SoftwareGPUTexture.d.ts.map +1 -1
- package/src/shade/device/mock/SoftwareGPUTexture.js +45 -8
- package/src/shade/device/mock/SoftwareGPUTextureView.d.ts +20 -1
- package/src/shade/device/mock/SoftwareGPUTextureView.d.ts.map +1 -1
- package/src/shade/device/mock/SoftwareGPUTextureView.js +28 -1
- package/src/shade/device/mock/recorded_binding_kind_mismatches.d.ts +20 -0
- package/src/shade/device/mock/recorded_binding_kind_mismatches.d.ts.map +1 -0
- package/src/shade/device/mock/recorded_binding_kind_mismatches.js +84 -0
- package/src/shade/device/mock/texture_copy.d.ts.map +1 -1
- package/src/shade/device/mock/texture_copy.js +41 -3
- package/src/shade/device/mock/texture_view_resource.d.ts +26 -0
- package/src/shade/device/mock/texture_view_resource.d.ts.map +1 -0
- package/src/shade/device/mock/texture_view_resource.js +47 -0
- package/src/shade/device/timing/GPUTimer.d.ts.map +1 -1
- package/src/shade/device/timing/GPUTimer.js +35 -21
- package/src/shade/playground/caldera/caldera_format.d.ts +28 -1
- package/src/shade/playground/caldera/caldera_format.d.ts.map +1 -1
- package/src/shade/playground/caldera/caldera_format.js +37 -0
- package/src/shade/playground/caldera/main.js +12 -2
- package/src/shade/playground/frame_rate_meter.d.ts +92 -0
- package/src/shade/playground/frame_rate_meter.d.ts.map +1 -0
- package/src/shade/playground/frame_rate_meter.js +147 -0
- package/src/shade/playground/particle_ecs/main.js +53 -7
- package/src/shade/playground/particle_ecs/moonlit_environment.js +2 -2
- package/src/shade/playground/particle_stats_readback.d.ts +58 -0
- package/src/shade/playground/particle_stats_readback.d.ts.map +1 -0
- package/src/shade/playground/particle_stats_readback.js +83 -0
- package/src/shade/playground/particle_system/main.js +378 -325
- package/src/shade/playground/skinned_blas_refit/main.d.ts.map +1 -1
- package/src/shade/playground/skinned_blas_refit/main.js +7 -2
- package/src/shade/playground/sponza_path_trace/main.d.ts.map +1 -1
- package/src/shade/playground/sponza_path_trace/main.js +398 -393
- package/src/shade/playground/volumetrics_froxel/main.d.ts.map +1 -1
- package/src/shade/playground/volumetrics_froxel/main.js +941 -936
- package/src/shade/renderer/GraphicsContext.d.ts.map +1 -1
- package/src/shade/renderer/GraphicsContext.js +7 -2
- package/src/shade/renderer/Renderer.d.ts +47 -1
- package/src/shade/renderer/Renderer.d.ts.map +1 -1
- package/src/shade/renderer/Renderer.js +224 -27
- package/src/shade/renderer/animation/ANIMATION_CLIP_STATE_STRUCT.d.ts +4 -7
- package/src/shade/renderer/animation/ANIMATION_CLIP_STATE_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/animation/ANIMATION_CLIP_STATE_STRUCT.js +19 -16
- package/src/shade/renderer/animation/ANIMATION_CURVE_HEADER_STRUCT.js +11 -11
- package/src/shade/renderer/animation/ANIMATION_DATABASE_SPEC.d.ts +14 -18
- package/src/shade/renderer/animation/ANIMATION_DATABASE_SPEC.d.ts.map +1 -1
- package/src/shade/renderer/animation/ANIMATION_DATABASE_SPEC.js +95 -24
- package/src/shade/renderer/animation/ANIMATION_SKIN_JOINT_STRUCT.d.ts +5 -4
- package/src/shade/renderer/animation/ANIMATION_SKIN_JOINT_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/animation/ANIMATION_SKIN_JOINT_STRUCT.js +7 -4
- package/src/shade/renderer/animation/ANIMATION_SKIN_STRUCT.d.ts +6 -12
- package/src/shade/renderer/animation/ANIMATION_SKIN_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/animation/ANIMATION_SKIN_STRUCT.js +9 -16
- package/src/shade/renderer/animation/ANIMATION_TRACK_BINDING_STRUCT.d.ts +6 -5
- package/src/shade/renderer/animation/ANIMATION_TRACK_BINDING_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/animation/ANIMATION_TRACK_BINDING_STRUCT.js +12 -5
- package/src/shade/renderer/animation/GPUAnimationManager.d.ts +80 -95
- package/src/shade/renderer/animation/GPUAnimationManager.d.ts.map +1 -1
- package/src/shade/renderer/animation/GPUAnimationManager.js +371 -606
- package/src/shade/renderer/animation/chunk_animation_curve_evaluate.d.ts +10 -14
- package/src/shade/renderer/animation/chunk_animation_curve_evaluate.d.ts.map +1 -1
- package/src/shade/renderer/animation/chunk_animation_curve_evaluate.js +40 -67
- package/src/shade/renderer/animation/chunk_pose_accumulator.d.ts.map +1 -1
- package/src/shade/renderer/animation/chunk_pose_accumulator.js +13 -4
- package/src/shade/renderer/animation/shader_animation_apply.d.ts +14 -8
- package/src/shade/renderer/animation/shader_animation_apply.d.ts.map +1 -1
- package/src/shade/renderer/animation/shader_animation_apply.js +129 -128
- package/src/shade/renderer/animation/skinning/GPUMeshSkinningContext.js +2 -2
- package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.d.ts +3 -2
- package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/SKINNING_BINDING_STRUCT.js +3 -2
- package/src/shade/renderer/animation/skinning/shader_skin_matrix_prep.d.ts +12 -7
- package/src/shade/renderer/animation/skinning/shader_skin_matrix_prep.d.ts.map +1 -1
- package/src/shade/renderer/animation/skinning/shader_skin_matrix_prep.js +107 -104
- package/src/shade/renderer/binding/BindingResource.d.ts +36 -1
- package/src/shade/renderer/binding/BindingResource.d.ts.map +1 -1
- package/src/shade/renderer/binding/BindingResource.js +36 -3
- package/src/shade/renderer/binding/BufferBinding.d.ts +8 -0
- package/src/shade/renderer/binding/BufferBinding.d.ts.map +1 -1
- package/src/shade/renderer/binding/BufferBinding.js +21 -0
- package/src/shade/renderer/buffer/table/GPUDatabase.d.ts +19 -0
- package/src/shade/renderer/buffer/table/GPUDatabase.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/GPUDatabase.js +114 -1
- package/src/shade/renderer/buffer/table/GPUDatabaseDefinition.d.ts +132 -1
- package/src/shade/renderer/buffer/table/GPUDatabaseDefinition.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/GPUDatabaseDefinition.js +384 -1
- package/src/shade/renderer/buffer/table/GPUDatabaseReadback.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/GPUDatabaseReadback.js +1332 -1323
- package/src/shade/renderer/buffer/table/GPUTableLink.d.ts +67 -0
- package/src/shade/renderer/buffer/table/GPUTableLink.d.ts.map +1 -0
- package/src/shade/renderer/buffer/table/GPUTableLink.js +76 -0
- package/src/shade/renderer/buffer/table/GPUTableRange.d.ts +72 -0
- package/src/shade/renderer/buffer/table/GPUTableRange.d.ts.map +1 -0
- package/src/shade/renderer/buffer/table/GPUTableRange.js +82 -0
- package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts +106 -5
- package/src/shade/renderer/buffer/table/GPUTypedTable.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/GPUTypedTable.js +444 -28
- package/src/shade/renderer/buffer/table/GPUTypedTableDescriptor.d.ts.map +1 -1
- package/src/shade/renderer/buffer/table/GPUTypedTableDescriptor.js +28 -5
- package/src/shade/renderer/buffer/table/GPU_DATABASE_NULL.d.ts +14 -0
- package/src/shade/renderer/buffer/table/GPU_DATABASE_NULL.d.ts.map +1 -0
- package/src/shade/renderer/buffer/table/GPU_DATABASE_NULL.js +13 -0
- package/src/shade/renderer/buffer/table/gpu_database_check_links.d.ts +80 -0
- package/src/shade/renderer/buffer/table/gpu_database_check_links.d.ts.map +1 -0
- package/src/shade/renderer/buffer/table/gpu_database_check_links.js +456 -0
- package/src/shade/renderer/buffer/table/gpu_table_field_word.d.ts +17 -0
- package/src/shade/renderer/buffer/table/gpu_table_field_word.d.ts.map +1 -0
- package/src/shade/renderer/buffer/table/gpu_table_field_word.js +111 -0
- package/src/shade/renderer/buffer/table/gpu_table_range_well_formed.d.ts +20 -0
- package/src/shade/renderer/buffer/table/gpu_table_range_well_formed.d.ts.map +1 -0
- package/src/shade/renderer/buffer/table/gpu_table_range_well_formed.js +27 -0
- package/src/shade/renderer/camera/CameraManager.d.ts +11 -0
- package/src/shade/renderer/camera/CameraManager.d.ts.map +1 -1
- package/src/shade/renderer/camera/CameraManager.js +18 -0
- package/src/shade/renderer/create_frame_loop.d.ts +16 -0
- package/src/shade/renderer/create_frame_loop.d.ts.map +1 -1
- package/src/shade/renderer/create_frame_loop.js +16 -0
- package/src/shade/renderer/deferred/chunk_shade_standard_material_direct.d.ts +23 -0
- package/src/shade/renderer/deferred/chunk_shade_standard_material_direct.d.ts.map +1 -1
- package/src/shade/renderer/deferred/chunk_shade_standard_material_direct.js +27 -32
- package/src/shade/renderer/deferred/chunk_shade_standard_material_direct_heavy.d.ts +9 -7
- package/src/shade/renderer/deferred/chunk_shade_standard_material_direct_heavy.d.ts.map +1 -1
- package/src/shade/renderer/deferred/chunk_shade_standard_material_direct_heavy.js +16 -108
- package/src/shade/renderer/dynamic/DynamicMeshAVBOITChannel.d.ts +135 -0
- package/src/shade/renderer/dynamic/DynamicMeshAVBOITChannel.d.ts.map +1 -0
- package/src/shade/renderer/dynamic/DynamicMeshAVBOITChannel.js +296 -0
- package/src/shade/renderer/dynamic/GPUDynamicMeshRenderer.d.ts +2 -2
- package/src/shade/renderer/dynamic/GPUDynamicMeshRenderer.d.ts.map +1 -1
- package/src/shade/renderer/dynamic/GPUDynamicMeshRenderer.js +10 -131
- package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.d.ts.map +1 -1
- package/src/shade/renderer/dynamic/GPUDynamicMeshResidency.js +185 -167
- package/src/shade/renderer/dynamic/GPUDynamicMeshResidencyTable.d.ts +49 -0
- package/src/shade/renderer/dynamic/GPUDynamicMeshResidencyTable.d.ts.map +1 -0
- package/src/shade/renderer/dynamic/GPUDynamicMeshResidencyTable.js +185 -0
- package/src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.d.ts +24 -0
- package/src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.d.ts.map +1 -0
- package/src/shade/renderer/dynamic/chunk_dynamic_mesh_avboit_vertex.js +49 -0
- package/src/shade/renderer/dynamic/chunk_dynamic_mesh_vertex.d.ts +18 -0
- package/src/shade/renderer/dynamic/chunk_dynamic_mesh_vertex.d.ts.map +1 -0
- package/src/shade/renderer/dynamic/chunk_dynamic_mesh_vertex.js +54 -0
- package/src/shade/renderer/dynamic/dynamic_mesh_live_bounds.d.ts +26 -0
- package/src/shade/renderer/dynamic/dynamic_mesh_live_bounds.d.ts.map +1 -0
- package/src/shade/renderer/dynamic/dynamic_mesh_live_bounds.js +96 -0
- package/src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.d.ts +102 -0
- package/src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.d.ts.map +1 -0
- package/src/shade/renderer/dynamic/graph_dynamic_mesh_avboit.js +364 -0
- package/src/shade/renderer/dynamic/shader_dynamic_mesh.d.ts.map +1 -1
- package/src/shade/renderer/dynamic/shader_dynamic_mesh.js +153 -177
- package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.d.ts +20 -0
- package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.d.ts.map +1 -0
- package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_draw.js +136 -0
- package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_occupancy.d.ts +20 -0
- package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_occupancy.d.ts.map +1 -0
- package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_occupancy.js +106 -0
- package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.d.ts +32 -0
- package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.d.ts.map +1 -0
- package/src/shade/renderer/dynamic/shader_dynamic_mesh_avboit_splat.js +163 -0
- package/src/shade/renderer/extension/RENDER_EXTENSION_DESIGN.md +13 -2
- package/src/shade/renderer/fow/GPUFogOfWarRenderer.d.ts.map +1 -1
- package/src/shade/renderer/fow/GPUFogOfWarRenderer.js +5 -14
- package/src/shade/renderer/fow/fow_obtain_mask.d.ts +17 -0
- package/src/shade/renderer/fow/fow_obtain_mask.d.ts.map +1 -0
- package/src/shade/renderer/fow/fow_obtain_mask.js +41 -0
- package/src/shade/renderer/frame_jitter_applies.d.ts +21 -0
- package/src/shade/renderer/frame_jitter_applies.d.ts.map +1 -0
- package/src/shade/renderer/frame_jitter_applies.js +23 -0
- package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/bvh/GPUGeometryBVHManager.js +128 -3
- package/src/shade/renderer/geometry/geometry_obtain_attribute.d.ts +42 -0
- package/src/shade/renderer/geometry/geometry_obtain_attribute.d.ts.map +1 -0
- package/src/shade/renderer/geometry/geometry_obtain_attribute.js +83 -0
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts +12 -0
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.d.ts.map +1 -1
- package/src/shade/renderer/geometry/meshlet/GPUMeshletManager.js +65 -0
- package/src/shade/renderer/geometry/meshlet/build/geometry_to_meshlets_greedy.d.ts.map +1 -1
- package/src/shade/renderer/geometry/meshlet/build/geometry_to_meshlets_greedy.js +4 -1
- package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.d.ts.map +1 -1
- package/src/shade/renderer/geometry/meshlet/build/meshoptimizer/geometry_to_meshlets_meshoptimizer.js +4 -1
- package/src/shade/renderer/geometry/normals/encode_normals_to_octahedral_u32.d.ts.map +1 -1
- package/src/shade/renderer/geometry/normals/encode_normals_to_octahedral_u32.js +4 -1
- package/src/shade/renderer/geometry/normals/geometry_build_tangents.d.ts.map +1 -1
- package/src/shade/renderer/geometry/normals/geometry_build_tangents.js +39 -1
- package/src/shade/renderer/geometry/util/geometry_merge.d.ts.map +1 -1
- package/src/shade/renderer/geometry/util/geometry_merge.js +18 -2
- package/src/shade/renderer/geometry/virtual/VIRTUAL_GEOMETRY_DESIGN.md +77 -39
- package/src/shade/renderer/geometry/virtual/build/gltf/gltf_collect_geometries.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/gltf/gltf_collect_geometries.js +31 -2
- package/src/shade/renderer/geometry/virtual/build/level/VGeoFrontier.d.ts +18 -0
- package/src/shade/renderer/geometry/virtual/build/level/VGeoFrontier.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/level/VGeoFrontier.js +19 -0
- package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupStep.d.ts +8 -0
- package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupStep.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/level/VGeoGroupStep.js +9 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_group_step.js +10 -1
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_leaf_frontier.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_leaf_frontier.js +4 -0
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_levels.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/build/level/vgeo_build_levels.js +12 -0
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/read/VGeoContainerReader.js +10 -1
- package/src/shade/renderer/geometry/virtual/format/read/vgeo_read_page.js +21 -0
- package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/format/vgeo_write_container.js +33 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoPageFetcher.js +63 -2
- package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts +17 -0
- package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/VGeoViewCut.js +39 -0
- package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.d.ts.map +1 -1
- package/src/shade/renderer/geometry/virtual/runtime/graph_vgeo_expand_instances_to_meshlets.js +7 -0
- package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v1/chunk_brick4_sh3_color_decode.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v1/chunk_brick4_sh3_color_decode.js +23 -2
- package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v1/chunk_brick4_sh3_color_decode_from_storage.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v1/chunk_brick4_sh3_color_decode_from_storage.js +22 -1
- package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v1/chunk_brick4_sh3_color_encode.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v1/chunk_brick4_sh3_color_encode.js +23 -2
- package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v1/chunk_brick4_sh3_color_encode_to_storage.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/brick4/gpu/encoding/v1/chunk_brick4_sh3_color_encode_to_storage.js +22 -1
- package/src/shade/renderer/global_illumination/lpv/lpv_visualise_probes.d.ts +2 -1
- package/src/shade/renderer/global_illumination/lpv/lpv_visualise_probes.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/lpv/lpv_visualise_probes.js +12 -53
- package/src/shade/renderer/global_illumination/probe/octahedral/convolve/graph_lvp_atlas_to_sh.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe/octahedral/convolve/graph_lvp_atlas_to_sh.js +2 -1
- package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_atlas_patch_texel_coord.d.ts +17 -0
- package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_atlas_patch_texel_coord.d.ts.map +1 -0
- package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_atlas_patch_texel_coord.js +38 -0
- package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_atlas_read_patch_texel.d.ts.map +1 -1
- package/src/shade/renderer/global_illumination/probe/octahedral/sample/chunk_lpv_atlas_read_patch_texel.js +16 -10
- package/src/shade/renderer/gpu_primitive/indirect/IndirectComputeCommandBuildPass.d.ts +1 -1
- package/src/shade/renderer/gpu_primitive/indirect/IndirectComputeCommandBuildPass.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/indirect/IndirectComputeCommandBuildPass.js +25 -14
- package/src/shade/renderer/gpu_primitive/indirect/NOTES.md +94 -0
- package/src/shade/renderer/gpu_primitive/indirect/WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION.d.ts +10 -7
- package/src/shade/renderer/gpu_primitive/indirect/WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION.d.ts.map +1 -1
- package/src/shade/renderer/gpu_primitive/indirect/WEBGPU_GUARANTEED_MAX_COMPUTE_WORKGROUPS_PER_DIMENSION.js +10 -7
- package/src/shade/renderer/light/GPULightCollection.d.ts.map +1 -1
- package/src/shade/renderer/light/GPULightCollection.js +22 -1
- package/src/shade/renderer/light/LIGHT_DATABASE_SPEC.d.ts.map +1 -1
- package/src/shade/renderer/light/LIGHT_DATABASE_SPEC.js +26 -0
- package/src/shade/renderer/light/cluster/chunk_cluster_keep_smallest.d.ts +21 -0
- package/src/shade/renderer/light/cluster/chunk_cluster_keep_smallest.d.ts.map +1 -0
- package/src/shade/renderer/light/cluster/chunk_cluster_keep_smallest.js +47 -0
- package/src/shade/renderer/light/cluster/shader_cluster_assign_lights.d.ts.map +1 -1
- package/src/shade/renderer/light/cluster/shader_cluster_assign_lights.js +12 -8
- package/src/shade/renderer/light/environment/equirectangular_zenith_first_direction_to_uv.d.ts +36 -0
- package/src/shade/renderer/light/environment/equirectangular_zenith_first_direction_to_uv.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/equirectangular_zenith_first_direction_to_uv.js +41 -0
- package/src/shade/renderer/light/environment/execute_filter_environment_map.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/execute_filter_environment_map.js +17 -1
- package/src/shade/renderer/light/environment/octahedral_uv_to_direction.d.ts +5 -13
- package/src/shade/renderer/light/environment/octahedral_uv_to_direction.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/octahedral_uv_to_direction.js +10 -30
- package/src/shade/renderer/light/environment/octahedral_z_pole_uv_to_direction.d.ts +31 -0
- package/src/shade/renderer/light/environment/octahedral_z_pole_uv_to_direction.d.ts.map +1 -0
- package/src/shade/renderer/light/environment/octahedral_z_pole_uv_to_direction.js +45 -0
- package/src/shade/renderer/light/environment/resample_cube_to_octahedral.js +2 -2
- package/src/shade/renderer/light/environment/resample_equirectangular_to_octahedral.d.ts.map +1 -1
- package/src/shade/renderer/light/environment/resample_equirectangular_to_octahedral.js +11 -8
- package/src/shade/renderer/light/model/SpotLight.d.ts +10 -1
- package/src/shade/renderer/light/model/SpotLight.d.ts.map +1 -1
- package/src/shade/renderer/light/model/SpotLight.js +11 -3
- package/src/shade/renderer/light/model/io/light_record_directional.d.ts.map +1 -1
- package/src/shade/renderer/light/model/io/light_record_directional.js +3 -1
- package/src/shade/renderer/light/model/io/light_record_point.d.ts.map +1 -1
- package/src/shade/renderer/light/model/io/light_record_point.js +3 -1
- package/src/shade/renderer/light/model/io/light_record_spot.d.ts.map +1 -1
- package/src/shade/renderer/light/model/io/light_record_spot.js +3 -1
- package/src/shade/renderer/loader/gltf/gltf_base_url.d.ts +20 -0
- package/src/shade/renderer/loader/gltf/gltf_base_url.d.ts.map +1 -0
- package/src/shade/renderer/loader/gltf/gltf_base_url.js +27 -0
- package/src/shade/renderer/loader/gltf/gltf_create_material.d.ts.map +1 -1
- package/src/shade/renderer/loader/gltf/gltf_create_material.js +50 -10
- package/src/shade/renderer/loader/gltf/load_gltf.d.ts +4 -0
- package/src/shade/renderer/loader/gltf/load_gltf.d.ts.map +1 -1
- package/src/shade/renderer/loader/gltf/load_gltf.js +28 -56
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts +1 -1
- package/src/shade/renderer/loader/gltf/tiny-gltf.d.ts.map +1 -1
- package/src/shade/renderer/loader/gltf/tiny-gltf.js +843 -843
- package/src/shade/renderer/material/GPUMaterialContext.d.ts +63 -26
- package/src/shade/renderer/material/GPUMaterialContext.d.ts.map +1 -1
- package/src/shade/renderer/material/GPUMaterialContext.js +255 -390
- package/src/shade/renderer/material/GPUMaterialManager.d.ts +51 -1
- package/src/shade/renderer/material/GPUMaterialManager.d.ts.map +1 -1
- package/src/shade/renderer/material/GPUMaterialManager.js +345 -91
- package/src/shade/renderer/material/ShadeMaterial.d.ts +21 -0
- package/src/shade/renderer/material/ShadeMaterial.d.ts.map +1 -1
- package/src/shade/renderer/material/ShadeMaterial.js +31 -0
- package/src/shade/renderer/material/resident/GPUResidentMaterialContext.d.ts.map +1 -1
- package/src/shade/renderer/material/resident/GPUResidentMaterialContext.js +25 -6
- package/src/shade/renderer/material/standard/SHADING_MATERIAL_RESOURCE_GROUP.d.ts +10 -0
- package/src/shade/renderer/material/standard/SHADING_MATERIAL_RESOURCE_GROUP.d.ts.map +1 -1
- package/src/shade/renderer/material/standard/SHADING_MATERIAL_RESOURCE_GROUP.js +14 -2
- package/src/shade/renderer/material/standard/STANDARD_MATERIAL_TEMPLATE.d.ts +12 -0
- package/src/shade/renderer/material/standard/STANDARD_MATERIAL_TEMPLATE.d.ts.map +1 -0
- package/src/shade/renderer/material/standard/STANDARD_MATERIAL_TEMPLATE.js +166 -0
- package/src/shade/renderer/material/standard/VT_MATERIAL_TEMPLATE.d.ts +10 -0
- package/src/shade/renderer/material/standard/VT_MATERIAL_TEMPLATE.d.ts.map +1 -0
- package/src/shade/renderer/material/standard/VT_MATERIAL_TEMPLATE.js +141 -0
- package/src/shade/renderer/material/standard/chunk_standard_material_surface.d.ts +29 -0
- package/src/shade/renderer/material/standard/chunk_standard_material_surface.d.ts.map +1 -0
- package/src/shade/renderer/material/standard/chunk_standard_material_surface.js +92 -0
- package/src/shade/renderer/material/standard/fragment_gbuffer.d.ts +74 -28
- package/src/shade/renderer/material/standard/fragment_gbuffer.d.ts.map +1 -1
- package/src/shade/renderer/material/standard/fragment_gbuffer.js +165 -67
- package/src/shade/renderer/material/standard/fragment_gbuffer_vt.d.ts +27 -18
- package/src/shade/renderer/material/standard/fragment_gbuffer_vt.d.ts.map +1 -1
- package/src/shade/renderer/material/standard/fragment_gbuffer_vt.js +70 -91
- package/src/shade/renderer/material/standard/material_gbuffer_vertex.d.ts +9 -6
- package/src/shade/renderer/material/standard/material_gbuffer_vertex.d.ts.map +1 -1
- package/src/shade/renderer/material/standard/material_gbuffer_vertex.js +13 -14
- package/src/shade/renderer/material/template/GPUMaterialServices.d.ts +73 -0
- package/src/shade/renderer/material/template/GPUMaterialServices.d.ts.map +1 -0
- package/src/shade/renderer/material/template/GPUMaterialServices.js +79 -0
- package/src/shade/renderer/material/template/ShadeMaterialTemplate.d.ts +170 -0
- package/src/shade/renderer/material/template/ShadeMaterialTemplate.d.ts.map +1 -0
- package/src/shade/renderer/material/template/ShadeMaterialTemplate.js +234 -0
- package/src/shade/renderer/material/template/chunk_material_surface.d.ts +47 -0
- package/src/shade/renderer/material/template/chunk_material_surface.d.ts.map +1 -0
- package/src/shade/renderer/material/template/chunk_material_surface.js +116 -0
- package/src/shade/renderer/material/template/flat_material_template_spec_support.d.ts +22 -0
- package/src/shade/renderer/material/template/flat_material_template_spec_support.d.ts.map +1 -0
- package/src/shade/renderer/material/template/flat_material_template_spec_support.js +78 -0
- package/src/shade/renderer/material/template/material_metadata_neutral.d.ts +15 -0
- package/src/shade/renderer/material/template/material_metadata_neutral.d.ts.map +1 -0
- package/src/shade/renderer/material/template/material_metadata_neutral.js +46 -0
- package/src/shade/renderer/material/template/material_template_of.d.ts +10 -0
- package/src/shade/renderer/material/template/material_template_of.d.ts.map +1 -0
- package/src/shade/renderer/material/template/material_template_of.js +20 -0
- package/src/shade/renderer/object_property/chunk_write_object_property.d.ts +5 -0
- package/src/shade/renderer/object_property/chunk_write_object_property.d.ts.map +1 -1
- package/src/shade/renderer/object_property/chunk_write_object_property.js +7 -1
- package/src/shade/renderer/object_property/chunk_write_object_property_node3d.d.ts +7 -1
- package/src/shade/renderer/object_property/chunk_write_object_property_node3d.d.ts.map +1 -1
- package/src/shade/renderer/object_property/chunk_write_object_property_node3d.js +9 -2
- package/src/shade/renderer/particles/DESIGN.md +7 -0
- package/src/shade/renderer/particles/data/PARTICLE_DATABASE_SPEC.d.ts.map +1 -1
- package/src/shade/renderer/particles/data/PARTICLE_DATABASE_SPEC.js +81 -68
- package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts +22 -3
- package/src/shade/renderer/particles/isa/ParticleVMISA.d.ts.map +1 -1
- package/src/shade/renderer/particles/isa/ParticleVMISA.js +30 -3
- package/src/shade/renderer/particles/isa/particle_assembly.js +41 -1
- package/src/shade/renderer/particles/optimizer/particle_program_analysis.d.ts +7 -1
- package/src/shade/renderer/particles/optimizer/particle_program_analysis.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/particle_program_analysis.js +23 -17
- package/src/shade/renderer/particles/optimizer/pass_allocate_registers.js +1 -1
- package/src/shade/renderer/particles/optimizer/pass_fold_constants.js +10 -9
- package/src/shade/renderer/particles/optimizer/pass_inline_constants.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_inline_constants.js +4 -3
- package/src/shade/renderer/particles/optimizer/pass_narrow_widths.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_narrow_widths.js +1 -1
- package/src/shade/renderer/particles/optimizer/pass_pack_registers.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_pack_registers.js +12 -4
- package/src/shade/renderer/particles/optimizer/pass_peephole.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_peephole.js +11 -10
- package/src/shade/renderer/particles/optimizer/pass_propagate_copies.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_propagate_copies.js +12 -10
- package/src/shade/renderer/particles/optimizer/pass_share_subexpressions.d.ts.map +1 -1
- package/src/shade/renderer/particles/optimizer/pass_share_subexpressions.js +12 -4
- package/src/shade/renderer/particles/runtime/ParticleEmitter.d.ts.map +1 -1
- package/src/shade/renderer/particles/runtime/ParticleEmitter.js +7 -0
- package/src/shade/renderer/particles/shaders/chunk_particle_avboit_contribution.d.ts +4 -0
- package/src/shade/renderer/particles/shaders/chunk_particle_avboit_contribution.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/chunk_particle_avboit_contribution.js +47 -88
- package/src/shade/renderer/particles/shaders/shader_particle_avboit_occupancy.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_avboit_occupancy.js +22 -68
- package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.d.ts.map +1 -1
- package/src/shade/renderer/particles/shaders/shader_particle_avboit_splat.js +5 -3
- package/src/shade/renderer/particles/vm/ParticleVMReference.d.ts.map +1 -1
- package/src/shade/renderer/particles/vm/ParticleVMReference.js +17 -1
- package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.d.ts.map +1 -1
- package/src/shade/renderer/path_tracer/shader/chunk_sample_material_data.js +12 -2
- package/src/shade/renderer/postprocess/TemporalJitterSequence.d.ts +44 -0
- package/src/shade/renderer/postprocess/TemporalJitterSequence.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/TemporalJitterSequence.js +104 -0
- package/src/shade/renderer/postprocess/chunk_find_nearest_depth.d.ts +25 -0
- package/src/shade/renderer/postprocess/chunk_find_nearest_depth.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/chunk_find_nearest_depth.js +74 -0
- package/src/shade/renderer/postprocess/denoise/shader_temporal_reprojection_luma.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/denoise/shader_temporal_reprojection_luma.js +19 -4
- package/src/shade/renderer/postprocess/dof/gather/shader_dof2_recombine.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/dof/gather/shader_dof2_recombine.js +12 -1
- package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/eye/GPUCameraExposureManager.js +8 -0
- package/src/shade/renderer/postprocess/eye/shader_autoexposure_adapt.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/eye/shader_autoexposure_adapt.js +18 -3
- package/src/shade/renderer/postprocess/eye/shader_autoexposure_read_histogram.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/eye/shader_autoexposure_read_histogram.js +17 -4
- package/src/shade/renderer/postprocess/gtao/GTAO_CONSTANTS.d.ts +29 -0
- package/src/shade/renderer/postprocess/gtao/GTAO_CONSTANTS.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/gtao/GTAO_CONSTANTS.js +69 -0
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.d.ts +4 -16
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao.js +10 -52
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.d.ts +0 -16
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/gtao/fragment_shader_gtao_with_irradiance.js +23 -55
- package/src/shade/renderer/postprocess/motion_blur/MotionBlur.d.ts +4 -1
- package/src/shade/renderer/postprocess/motion_blur/MotionBlur.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/motion_blur/MotionBlur.js +4 -1
- package/src/shade/renderer/postprocess/motion_blur/chunk_motion_blur_resolution.d.ts +18 -0
- package/src/shade/renderer/postprocess/motion_blur/chunk_motion_blur_resolution.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/motion_blur/chunk_motion_blur_resolution.js +43 -0
- package/src/shade/renderer/postprocess/motion_blur/graph_postprocess_motion_blur.d.ts +5 -1
- package/src/shade/renderer/postprocess/motion_blur/graph_postprocess_motion_blur.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/motion_blur/graph_postprocess_motion_blur.js +12 -2
- package/src/shade/renderer/postprocess/motion_blur/shader_motion_blur_reconstruct.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/motion_blur/shader_motion_blur_reconstruct.js +33 -6
- package/src/shade/renderer/postprocess/nss/NSS.d.ts +16 -8
- package/src/shade/renderer/postprocess/nss/NSS.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/nss/NSS.js +37 -35
- package/src/shade/renderer/postprocess/nss/chunk_nss_find_nearest_depth.d.ts +2 -2
- package/src/shade/renderer/postprocess/nss/chunk_nss_find_nearest_depth.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/nss/chunk_nss_find_nearest_depth.js +28 -61
- package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/nss/shader_nss_postprocess.js +296 -291
- package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/nss/shader_nss_preprocess.js +13 -0
- package/src/shade/renderer/postprocess/ssr/SSR.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/SSR.js +9 -7
- package/src/shade/renderer/postprocess/ssr/depth_max_shader.d.ts +14 -0
- package/src/shade/renderer/postprocess/ssr/depth_max_shader.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/depth_max_shader.js +53 -25
- package/src/shade/renderer/postprocess/ssr/graph_build_depth_max_pyramid.d.ts +11 -1
- package/src/shade/renderer/postprocess/ssr/graph_build_depth_max_pyramid.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/graph_build_depth_max_pyramid.js +11 -1
- package/src/shade/renderer/postprocess/ssr/prefilter/NOTES.md +46 -0
- package/src/shade/renderer/postprocess/ssr/prefilter/shader_ssr_prefilter.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/prefilter/shader_ssr_prefilter.js +7 -0
- package/src/shade/renderer/postprocess/ssr/shader/chunk_ssr_depth_thickness.d.ts +32 -0
- package/src/shade/renderer/postprocess/ssr/shader/chunk_ssr_depth_thickness.d.ts.map +1 -0
- package/src/shade/renderer/postprocess/ssr/shader/chunk_ssr_depth_thickness.js +41 -0
- package/src/shade/renderer/postprocess/ssr/ssr_trace_shader.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/ssr/ssr_trace_shader.js +11 -6
- package/src/shade/renderer/postprocess/taa/TAA.d.ts +13 -4
- package/src/shade/renderer/postprocess/taa/TAA.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/taa/TAA.js +29 -48
- package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.d.ts +11 -0
- package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/taa/chunk_taa_tonemap.js +25 -4
- package/src/shade/renderer/postprocess/taa/shader_depth_occlusion_clip.d.ts +8 -0
- package/src/shade/renderer/postprocess/taa/shader_depth_occlusion_clip.d.ts.map +1 -1
- package/src/shade/renderer/postprocess/taa/shader_depth_occlusion_clip.js +14 -42
- package/src/shade/renderer/rasterize/RasterizationJob.d.ts +4 -2
- package/src/shade/renderer/rasterize/RasterizationJob.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/RasterizationJob.js +3 -1
- package/src/shade/renderer/rasterize/TemplatePassDescriptor.d.ts +57 -0
- package/src/shade/renderer/rasterize/TemplatePassDescriptor.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/TemplatePassDescriptor.js +133 -0
- package/src/shade/renderer/rasterize/bucket/construct_primitive_state.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/construct_primitive_state.js +17 -0
- package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/prepare_meshlet_draw_commands_by_material.js +30 -4
- package/src/shade/renderer/rasterize/bucket/shader_count_meshlets_by_material.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/shader_count_meshlets_by_material.js +74 -68
- package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/shader_read_out_bucket.js +11 -1
- package/src/shade/renderer/rasterize/bucket/shader_sort_meshlets_by_material.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/bucket/shader_sort_meshlets_by_material.js +70 -64
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way.js +3 -4
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/cull/hzb/shader_hzb_meshlet_filter_1way_full.js +8 -2
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_count_by_rasterization_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_count_by_rasterization_bucket.js +3 -4
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_extract_bucket.js +7 -5
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/bucket/meshlet/shader_meshlets_rasterization_bucket_sort.js +3 -4
- package/src/shade/renderer/rasterize/expand/mesh/shader_mesh_expand_to_meshlets_prefix.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/mesh/shader_mesh_expand_to_meshlets_prefix.js +3 -4
- package/src/shade/renderer/rasterize/expand/mesh/shader_prefix_sum_to_command.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/mesh/shader_prefix_sum_to_command.js +5 -2
- package/src/shade/renderer/rasterize/expand/pass1/filter_meshlets.2-way.compute.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/expand/pass1/filter_meshlets.2-way.compute.js +3 -4
- package/src/shade/renderer/rasterize/forward/SHADING_SCENE_RESOURCE_GROUP.d.ts +20 -0
- package/src/shade/renderer/rasterize/forward/SHADING_SCENE_RESOURCE_GROUP.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/forward/SHADING_SCENE_RESOURCE_GROUP.js +25 -0
- package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_brick4.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_brick4.js +2 -1
- package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_ibl.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/forward/chunk_forward_shade_standard_fragment_ibl.js +2 -1
- package/src/shade/renderer/rasterize/forward/forward_template_pipeline.d.ts +40 -0
- package/src/shade/renderer/rasterize/forward/forward_template_pipeline.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/forward/forward_template_pipeline.js +86 -0
- package/src/shade/renderer/rasterize/forward/vertex_shader_chunk.d.ts +11 -0
- package/src/shade/renderer/rasterize/forward/vertex_shader_chunk.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/forward/vertex_shader_chunk.js +13 -2
- package/src/shade/renderer/rasterize/native/alpha_tested_pass_resources.d.ts +59 -1
- package/src/shade/renderer/rasterize/native/alpha_tested_pass_resources.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/alpha_tested_pass_resources.js +109 -7
- package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts +16 -1
- package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/AVBOITSideChannel.js +13 -1
- package/src/shade/renderer/rasterize/native/avboit/AVBOIT_LEDGER.md +247 -0
- package/src/shade/renderer/rasterize/native/avboit/AVBOIT_PLAN_2026_09_03.md +20 -2
- package/src/shade/renderer/rasterize/native/avboit/avboit_draw_fragment_body.js +1 -1
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_coverage.d.ts +17 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_coverage.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_coverage.js +25 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_fold_pairs.d.ts +4 -5
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_fold_pairs.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_fold_pairs.js +7 -6
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_occupancy_mark.d.ts +17 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_occupancy_mark.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_occupancy_mark.js +51 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_premultiplied_contribution.d.ts +23 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_premultiplied_contribution.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/native/avboit/chunk_avboit_premultiplied_contribution.js +77 -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 +16 -20
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_brick4.d.ts +8 -2
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_brick4.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_brick4.js +57 -43
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_ibl.d.ts +8 -2
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_ibl.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_draw_ibl.js +57 -43
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_occupancy.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_occupancy.js +8 -2
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.d.ts +7 -2
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/avboit/shader_avboit_splat.js +67 -58
- package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_alpha_tested_pass_descriptor.d.ts +8 -2
- package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_alpha_tested_pass_descriptor.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/depth/shadow_rasterization_alpha_tested_pass_descriptor.js +186 -156
- package/src/shade/renderer/rasterize/native/graph_rasterize_meshes_alpha_tested.d.ts +2 -2
- package/src/shade/renderer/rasterize/native/graph_rasterize_meshes_alpha_tested.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/graph_rasterize_meshes_alpha_tested.js +36 -28
- package/src/shade/renderer/rasterize/native/material_draw_indirect.d.ts +14 -12
- package/src/shade/renderer/rasterize/native/material_draw_indirect.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/material_draw_indirect.js +29 -23
- package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/oit/graph_rasterize_meshes_transparent_oit.js +16 -22
- package/src/shade/renderer/rasterize/native/oit/oit_resolve_fragment_body.d.ts +33 -0
- package/src/shade/renderer/rasterize/native/oit/oit_resolve_fragment_body.d.ts.map +1 -0
- package/src/shade/renderer/rasterize/native/oit/oit_resolve_fragment_body.js +123 -0
- package/src/shade/renderer/rasterize/native/oit/shader_oit_generate_moments.d.ts +7 -2
- package/src/shade/renderer/rasterize/native/oit/shader_oit_generate_moments.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/oit/shader_oit_generate_moments.js +227 -218
- package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments.d.ts +8 -2
- package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments.js +112 -180
- package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments_ibl.d.ts +8 -2
- package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments_ibl.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/oit/shader_oit_resolve_moments_ibl.js +110 -178
- package/src/shade/renderer/rasterize/native/viz/viz_rasterization_alpha_tested_pass_descriptor.d.ts +7 -2
- package/src/shade/renderer/rasterize/native/viz/viz_rasterization_alpha_tested_pass_descriptor.d.ts.map +1 -1
- package/src/shade/renderer/rasterize/native/viz/viz_rasterization_alpha_tested_pass_descriptor.js +242 -204
- package/src/shade/renderer/restir/reservoir/shader.d.ts.map +1 -1
- package/src/shade/renderer/restir/reservoir/shader.js +27 -1
- package/src/shade/renderer/scene/GPUSceneContext.d.ts +2 -1
- package/src/shade/renderer/scene/GPUSceneContext.d.ts.map +1 -1
- package/src/shade/renderer/scene/GPUSceneContext.js +11 -9
- package/src/shade/renderer/scene/SCENE_DATABASE_SPEC.js +22 -0
- package/src/shade/renderer/scene/SceneManager.d.ts +10 -0
- package/src/shade/renderer/scene/SceneManager.d.ts.map +1 -1
- package/src/shade/renderer/scene/SceneManager.js +17 -0
- package/src/shade/renderer/scene/rows/GPUEntityBoundsReadback.d.ts.map +1 -1
- package/src/shade/renderer/scene/rows/GPUEntityBoundsReadback.js +164 -144
- package/src/shade/renderer/scene/rows/GPUSceneRows.d.ts +10 -0
- package/src/shade/renderer/scene/rows/GPUSceneRows.d.ts.map +1 -1
- package/src/shade/renderer/scene/rows/GPUSceneRows.js +14 -0
- package/src/shade/renderer/scene/serialization/serialize_scene.d.ts.map +1 -1
- package/src/shade/renderer/scene/serialization/serialize_scene.js +2 -6
- package/src/shade/renderer/shader/ComputeShader.d.ts +5 -0
- package/src/shade/renderer/shader/ComputeShader.d.ts.map +1 -1
- package/src/shade/renderer/shader/ComputeShader.js +358 -353
- package/src/shade/renderer/shader/chunk/atmosphere/chunk_integrate_scattering.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/atmosphere/chunk_integrate_scattering.js +15 -1
- package/src/shade/renderer/shader/chunk/binary/chunk_encode_f16.d.ts +11 -2
- package/src/shade/renderer/shader/chunk/binary/chunk_encode_f16.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/binary/chunk_encode_f16.js +33 -13
- package/src/shade/renderer/shader/chunk/brdf/chunk_D_GGX.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/brdf/chunk_D_GGX.js +31 -3
- package/src/shade/renderer/shader/chunk/bvh/morton/chunk_decode32_morton2.d.ts +10 -1
- package/src/shade/renderer/shader/chunk/bvh/morton/chunk_decode32_morton2.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/bvh/morton/chunk_decode32_morton2.js +23 -8
- package/src/shade/renderer/shader/chunk/camera/chunk_pixel_radius_to_world.d.ts +8 -1
- package/src/shade/renderer/shader/chunk/camera/chunk_pixel_radius_to_world.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/camera/chunk_pixel_radius_to_world.js +12 -5
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_distance_to_ray.d.ts +15 -1
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_distance_to_ray.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_distance_to_ray.js +24 -28
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_distance_to_ray_v2.d.ts +5 -0
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_distance_to_ray_v2.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_distance_to_ray_v2.js +18 -13
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_intersects_ray.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_intersects_ray.js +1 -47
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_raycast.d.ts +10 -0
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_raycast.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_raycast.js +23 -8
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_raycast_positive.d.ts +7 -0
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_raycast_positive.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_raycast_positive.js +12 -25
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_slab_span.d.ts +32 -0
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_slab_span.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_slab_span.js +52 -0
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_view_depth_range.d.ts +20 -0
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_view_depth_range.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/geometry/aabb3/chunk_aabb3_view_depth_range.js +42 -0
- package/src/shade/renderer/shader/chunk/geometry/octahedron/chunk_octahedral_uv_wrap.d.ts +10 -1
- package/src/shade/renderer/shader/chunk/geometry/octahedron/chunk_octahedral_uv_wrap.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/octahedron/chunk_octahedral_uv_wrap.js +18 -3
- package/src/shade/renderer/shader/chunk/geometry/quaternion/chunk_quat_encode_u32.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/geometry/quaternion/chunk_quat_encode_u32.js +8 -4
- package/src/shade/renderer/shader/chunk/grid/chunk_folded_workgroup_index.d.ts +24 -0
- package/src/shade/renderer/shader/chunk/grid/chunk_folded_workgroup_index.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/grid/chunk_folded_workgroup_index.js +36 -0
- package/src/shade/renderer/shader/chunk/grid/chunk_grid3d_to_index.d.ts +6 -0
- package/src/shade/renderer/shader/chunk/grid/chunk_grid3d_to_index.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/grid/chunk_grid3d_to_index.js +6 -0
- package/src/shade/renderer/shader/chunk/light/INCIDENT_LIGHT_STRUCT.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/light/INCIDENT_LIGHT_STRUCT.js +6 -1
- package/src/shade/renderer/shader/chunk/light/io/chunk_get_spot_light_info.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/light/io/chunk_get_spot_light_info.js +6 -1
- package/src/shade/renderer/shader/chunk/material/chunk_albedo_unpremultiply.d.ts +24 -0
- package/src/shade/renderer/shader/chunk/material/chunk_albedo_unpremultiply.d.ts.map +1 -0
- package/src/shade/renderer/shader/chunk/material/chunk_albedo_unpremultiply.js +31 -0
- package/src/shade/renderer/shader/chunk/random/pcg/chunk_pcg2d.js +2 -2
- package/src/shade/renderer/shader/chunk/random/pcg/chunk_pcg3d16.js +1 -1
- package/src/shade/renderer/shader/chunk/random/pcg/chunk_pcg4d.js +1 -1
- package/src/shade/renderer/shader/chunk/screen_space/chunk_ffx_sssr_validate_hit.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/screen_space/chunk_ffx_sssr_validate_hit.js +8 -4
- package/src/shade/renderer/shader/chunk/sdf/chunk_mesh_sdf_soft_shadow.d.ts.map +1 -1
- package/src/shade/renderer/shader/chunk/sdf/chunk_mesh_sdf_soft_shadow.js +17 -3
- package/src/shade/renderer/shader/graph/compute/graph_compute_indirect_pass.d.ts +4 -0
- package/src/shade/renderer/shader/graph/compute/graph_compute_indirect_pass.d.ts.map +1 -1
- package/src/shade/renderer/shader/graph/compute/graph_compute_indirect_pass.js +4 -0
- package/src/shade/renderer/shader/pass/RenderPassDescriptor.d.ts +8 -0
- package/src/shade/renderer/shader/pass/RenderPassDescriptor.d.ts.map +1 -1
- package/src/shade/renderer/shader/pass/RenderPassDescriptor.js +203 -192
- package/src/shade/renderer/shader/resource/ShaderResourceGroupDescriptor.d.ts.map +1 -1
- package/src/shade/renderer/shader/resource/ShaderResourceGroupDescriptor.js +12 -0
- package/src/shade/renderer/shader/type/WebGPUArray.d.ts.map +1 -1
- package/src/shade/renderer/shader/type/WebGPUArray.js +25 -1
- package/src/shade/renderer/shader/type/queue_typed_buffer_update.d.ts.map +1 -1
- package/src/shade/renderer/shader/type/queue_typed_buffer_update.js +15 -0
- package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.d.ts.map +1 -1
- package/src/shade/renderer/shadow/map/GPUSceneShadowmapContext.js +10 -9
- package/src/shade/renderer/shadow/map/ShadowmapDrawSelector.d.ts +12 -2
- package/src/shade/renderer/shadow/map/ShadowmapDrawSelector.d.ts.map +1 -1
- package/src/shade/renderer/shadow/map/ShadowmapDrawSelector.js +210 -196
- package/src/shade/renderer/shadow/map/csm/shader/shader_csm_caster_range.d.ts +10 -3
- package/src/shade/renderer/shadow/map/csm/shader/shader_csm_caster_range.d.ts.map +1 -1
- package/src/shade/renderer/shadow/map/csm/shader/shader_csm_caster_range.js +219 -194
- package/src/shade/renderer/shadow/map/shadowmap_budget_carry_over.d.ts +32 -0
- package/src/shade/renderer/shadow/map/shadowmap_budget_carry_over.d.ts.map +1 -0
- package/src/shade/renderer/shadow/map/shadowmap_budget_carry_over.js +47 -0
- package/src/shade/renderer/shadow/vsm/VirtualShadowMap.d.ts.map +1 -1
- package/src/shade/renderer/shadow/vsm/VirtualShadowMap.js +11 -1
- package/src/shade/renderer/texture/ShadeTexture.d.ts +16 -0
- package/src/shade/renderer/texture/ShadeTexture.d.ts.map +1 -1
- package/src/shade/renderer/texture/ShadeTexture.js +17 -0
- package/src/shade/renderer/texture/TextureManager.d.ts +22 -5
- package/src/shade/renderer/texture/TextureManager.d.ts.map +1 -1
- package/src/shade/renderer/texture/TextureManager.js +109 -6
- package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.d.ts.map +1 -1
- package/src/shade/renderer/texture/bindless/GPUBindlessTextureManager.js +8 -2
- package/src/shade/renderer/texture/download_texture_data.d.ts.map +1 -1
- package/src/shade/renderer/texture/download_texture_data.js +12 -4
- package/src/shade/renderer/texture/encode/shader_texture_encode_astc_4x4.d.ts.map +1 -1
- package/src/shade/renderer/texture/encode/shader_texture_encode_astc_4x4.js +66 -63
- package/src/shade/renderer/texture/encode/shader_texture_encode_bc1.d.ts.map +1 -1
- package/src/shade/renderer/texture/encode/shader_texture_encode_bc1.js +63 -60
- package/src/shade/renderer/texture/encode/shader_texture_encode_bc4.d.ts.map +1 -1
- package/src/shade/renderer/texture/encode/shader_texture_encode_bc4.js +79 -76
- package/src/shade/renderer/texture/encode/shader_texture_encode_bc4_snorm.d.ts.map +1 -1
- package/src/shade/renderer/texture/encode/shader_texture_encode_bc4_snorm.js +67 -64
- package/src/shade/renderer/texture/encode/shader_texture_encode_bc5.d.ts.map +1 -1
- package/src/shade/renderer/texture/encode/shader_texture_encode_bc5.js +70 -67
- package/src/shade/renderer/texture/encode/shader_texture_encode_bc5_snorm.d.ts.map +1 -1
- package/src/shade/renderer/texture/encode/shader_texture_encode_bc5_snorm.js +66 -63
- package/src/shade/renderer/texture/encode/shader_texture_encode_bc6h.d.ts.map +1 -1
- package/src/shade/renderer/texture/encode/shader_texture_encode_bc6h.js +65 -62
- package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.d.ts.map +1 -1
- package/src/shade/renderer/texture/encode/shader_texture_encode_bc7.js +61 -58
- package/src/shade/renderer/texture/format/texture_format_from_shade_image.d.ts +7 -1
- package/src/shade/renderer/texture/format/texture_format_from_shade_image.d.ts.map +1 -1
- package/src/shade/renderer/texture/format/texture_format_from_shade_image.js +100 -95
- package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.d.ts.map +1 -1
- package/src/shade/renderer/texture/mipmaps/WebGPUMipmapGenerator.js +59 -68
- package/src/shade/renderer/texture/mipmaps/filters/mipmap_shader_code_wronski2021.d.ts +30 -1
- package/src/shade/renderer/texture/mipmaps/filters/mipmap_shader_code_wronski2021.d.ts.map +1 -1
- package/src/shade/renderer/texture/mipmaps/filters/mipmap_shader_code_wronski2021.js +37 -20
- package/src/shade/renderer/texture/texture_descriptor_from_texture_shade.js +73 -73
- package/src/shade/renderer/view/ViewManager.d.ts +8 -0
- package/src/shade/renderer/view/ViewManager.d.ts.map +1 -1
- package/src/shade/renderer/view/ViewManager.js +15 -0
- package/src/shade/renderer/volumetrics/GPUViewVolumetrics.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/GPUViewVolumetrics.js +516 -507
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_scattering_lut.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/shader_volumetrics_build_scattering_lut.js +272 -260
- package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.d.ts.map +1 -1
- package/src/shade/renderer/volumetrics/taa/shader_volumetrics_taa.js +160 -134
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts +3 -0
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/WGSLJavaScriptCompiler.js +243 -62
- package/src/shade/wgsl/emulator/WGSLLanguageCore.d.ts.map +1 -1
- package/src/shade/wgsl/emulator/WGSLLanguageCore.js +110 -7
- package/src/shade/wgsl/validate_wgsl_source.d.ts.map +1 -1
- package/src/shade/wgsl/validate_wgsl_source.js +57 -0
- package/src/view/asset/AssetLoaderStatusView.d.ts.map +1 -1
- package/src/view/asset/AssetLoaderStatusView.js +8 -0
- package/src/view/common/LabelView.d.ts.map +1 -1
- package/src/view/common/LabelView.js +4 -0
- package/src/view/common/ListView.d.ts +6 -2
- package/src/view/common/ListView.d.ts.map +1 -1
- package/src/view/common/ListView.js +27 -7
- package/src/view/common/TabbedView.d.ts.map +1 -1
- package/src/view/common/TabbedView.js +8 -0
- package/src/view/common/VirtualListView.d.ts.map +1 -1
- package/src/view/common/VirtualListView.js +17 -1
- package/src/view/common/dnd/DropTarget.d.ts.map +1 -1
- package/src/view/common/dnd/DropTarget.js +18 -0
- package/src/view/elements/DropDownSelectionView.d.ts.map +1 -1
- package/src/view/elements/DropDownSelectionView.js +8 -0
- package/src/view/elements/image/SvgImageView.d.ts.map +1 -1
- package/src/view/elements/image/SvgImageView.js +8 -0
- package/src/view/elements/navigation/ViewStack.d.ts.map +1 -1
- package/src/view/elements/navigation/ViewStack.js +4 -0
- package/src/view/elements/notify/NotificationView.d.ts.map +1 -1
- package/src/view/elements/notify/NotificationView.js +4 -0
- package/src/view/elements/progress/segmented/SegmentedResourceBarView.d.ts.map +1 -1
- package/src/view/elements/progress/segmented/SegmentedResourceBarView.js +8 -0
- package/src/view/elements/radial/RadialMenu.d.ts.map +1 -1
- package/src/view/elements/radial/RadialMenu.js +4 -0
- package/src/view/minimap/Minimap.d.ts.map +1 -1
- package/src/view/minimap/Minimap.js +8 -0
- package/src/view/minimap/MinimapCanvasView.d.ts.map +1 -1
- package/src/view/minimap/MinimapCanvasView.js +21 -1
- package/src/view/minimap/dom/MinimapCameraView.d.ts.map +1 -1
- package/src/view/minimap/dom/MinimapCameraView.js +232 -220
- package/src/view/minimap/dom/MinimapMarkerView.d.ts.map +1 -1
- package/src/view/minimap/dom/MinimapMarkerView.js +8 -0
- package/src/view/minimap/minimap_focus_area.d.ts +5 -0
- package/src/view/minimap/minimap_focus_area.d.ts.map +1 -1
- package/src/view/minimap/minimap_focus_area.js +22 -0
- package/src/view/tooltip/TooltipManager.d.ts.map +1 -1
- package/src/view/tooltip/TooltipManager.js +16 -4
- package/src/core/geom/3d/atlas/atlas_bench_lib.js +0 -315
- package/src/engine/graphics/ecs/mesh/MeshEvents.d.ts +0 -6
- package/src/engine/graphics/ecs/mesh/MeshEvents.d.ts.map +0 -1
- package/src/engine/graphics/ecs/mesh/MeshEvents.js +0 -16
- package/src/engine/graphics/ecs/mesh/commonObject3DFastMatrixUpdate.d.ts +0 -2
- package/src/engine/graphics/ecs/mesh/commonObject3DFastMatrixUpdate.d.ts.map +0 -1
- package/src/engine/graphics/ecs/mesh/commonObject3DFastMatrixUpdate.js +0 -37
- package/src/engine/graphics/ecs/mesh/copyToVector3.d.ts +0 -8
- package/src/engine/graphics/ecs/mesh/copyToVector3.d.ts.map +0 -1
- package/src/engine/graphics/ecs/mesh/copyToVector3.js +0 -18
- package/src/engine/graphics/ecs/mesh/object3DFastMatrixUpdate.d.ts +0 -6
- package/src/engine/graphics/ecs/mesh/object3DFastMatrixUpdate.d.ts.map +0 -1
- package/src/engine/graphics/ecs/mesh/object3DFastMatrixUpdate.js +0 -18
- package/src/engine/graphics/ecs/mesh/rootObject3DFastMatrixUpdate.d.ts +0 -6
- package/src/engine/graphics/ecs/mesh/rootObject3DFastMatrixUpdate.d.ts.map +0 -1
- package/src/engine/graphics/ecs/mesh/rootObject3DFastMatrixUpdate.js +0 -14
- package/src/engine/graphics/ecs/mesh/setMesh.d.ts +0 -16
- package/src/engine/graphics/ecs/mesh/setMesh.d.ts.map +0 -1
- package/src/engine/graphics/ecs/mesh/setMesh.js +0 -55
- package/src/engine/graphics/ecs/mesh/skeleton/BoneMapping.d.ts +0 -13
- package/src/engine/graphics/ecs/mesh/skeleton/BoneMapping.d.ts.map +0 -1
- package/src/engine/graphics/ecs/mesh/skeleton/BoneMapping.js +0 -99
- package/src/engine/graphics/ecs/mesh/skeleton/HumanoidBoneType.d.ts +0 -25
- package/src/engine/graphics/ecs/mesh/skeleton/HumanoidBoneType.d.ts.map +0 -1
- package/src/engine/graphics/ecs/mesh/skeleton/HumanoidBoneType.js +0 -29
- package/src/engine/graphics/ecs/mesh/updateMeshTransform.d.ts +0 -6
- package/src/engine/graphics/ecs/mesh/updateMeshTransform.d.ts.map +0 -1
- package/src/engine/graphics/ecs/mesh/updateMeshTransform.js +0 -15
- package/src/engine/graphics/ecs/mesh/updateNodeByTransformAndBBB.d.ts +0 -8
- package/src/engine/graphics/ecs/mesh/updateNodeByTransformAndBBB.d.ts.map +0 -1
- package/src/engine/graphics/ecs/mesh/updateNodeByTransformAndBBB.js +0 -14
- package/src/engine/graphics3/terrain/GPUTerrainSplatRenderer.js +0 -481
- package/src/engine/graphics3/terrain/pack_terrain_row_table.js +0 -48
- package/src/engine/graphics3/terrain/shader_terrain_splat.js +0 -215
- package/src/shade/renderer/animation/ANIMATION_BOUND_TRACK_GROUP_STRUCT.js +0 -57
- package/src/shade/renderer/animation/ANIMATION_KEYFRAME_BLOCK_STRUCT.js +0 -50
- package/src/shade/renderer/animation/ANIMATION_SKIN_JOINT_BLOCK_STRUCT.js +0 -62
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_CREASE_ANGLE.d.ts +0 -46
- package/src/shade/renderer/geometry/virtual/build/mesh/VGEO_CREASE_ANGLE.d.ts.map +0 -1
|
@@ -11,15 +11,21 @@ import { NetworkSystem } from "./ecs/NetworkSystem.js";
|
|
|
11
11
|
import { NetworkIdentitySerializationAdapter, } from "./ecs/serialization/NetworkIdentitySerializationAdapter.js";
|
|
12
12
|
import { NetworkPeer, ResumeRejectReason, } from "./orchestrator/NetworkPeer.js";
|
|
13
13
|
import { ServerAuthoritativeClient } from "./orchestrator/ServerAuthoritativeClient.js";
|
|
14
|
-
import { ServerAuthoritativeServer } from "./orchestrator/ServerAuthoritativeServer.js";
|
|
14
|
+
import { LateInput, ServerAuthoritativeServer } from "./orchestrator/ServerAuthoritativeServer.js";
|
|
15
15
|
import { OwnerAwareScope } from "./replication/ScopeFilter.js";
|
|
16
16
|
import { BinaryInterpolationAdapter, InterpolationKind, } from "../interpolation/BinaryInterpolationAdapter.js";
|
|
17
|
+
import { Interpoland } from "../interpolation/Interpoland.js";
|
|
18
|
+
import { Interpolated, INTERPOLATION_SOURCE_LOCAL } from "../interpolation/Interpolated.js";
|
|
17
19
|
import { InterpolationLog } from "../interpolation/InterpolationLog.js";
|
|
20
|
+
import { InterpolationSystem } from "../interpolation/InterpolationSystem.js";
|
|
18
21
|
import { SimAction } from "./sim/SimAction.js";
|
|
19
22
|
import { snapshotter_emit } from "./sim/Snapshotter.js";
|
|
23
|
+
import { PredictionHistory } from "./state/PredictionHistory.js";
|
|
20
24
|
import { AdaptiveRenderDelay } from "./time/AdaptiveRenderDelay.js";
|
|
21
25
|
import { RenderPlayout } from "./time/RenderPlayout.js";
|
|
22
26
|
import { TimeDilation } from "./time/TimeDilation.js";
|
|
27
|
+
import { DeferredTransport } from "./transport/DeferredTransport.js";
|
|
28
|
+
import { CorrectionTarget, HOST_VALUE_CORRECTION } from "./correction/Correction.js";
|
|
23
29
|
|
|
24
30
|
/**
|
|
25
31
|
* Roles a session can occupy. The orchestrator it wires up underneath is
|
|
@@ -44,10 +50,38 @@ export const NetworkSessionRole = Object.freeze({
|
|
|
44
50
|
Host: 'host',
|
|
45
51
|
});
|
|
46
52
|
|
|
47
|
-
|
|
53
|
+
/**
|
|
54
|
+
* How a client brings the entities it predicts back in line with the host's authoritative state.
|
|
55
|
+
*
|
|
56
|
+
* @readonly @enum {string}
|
|
57
|
+
*/
|
|
58
|
+
export const NetworkSessionReconcile = Object.freeze({
|
|
59
|
+
/**
|
|
60
|
+
* Compare the host's state for frame S with what this client predicted for S. Equal: nothing
|
|
61
|
+
* to do. Different: carry the difference observed at S into the present, component by
|
|
62
|
+
* component, as each component's {@link Correction} says — a pose by its offset and turn, a
|
|
63
|
+
* velocity by its difference, a value with no notion of difference by the host's value. No
|
|
64
|
+
* rewind, no replay, so it holds for state produced by physics and any other fixed-step system,
|
|
65
|
+
* not only by actions.
|
|
66
|
+
*/
|
|
67
|
+
Correct: 'correct',
|
|
68
|
+
/**
|
|
69
|
+
* Rewind the action log to S, apply the host's state, and re-execute this client's input for
|
|
70
|
+
* every frame since. Exact when everything predicted is produced by deterministic actions; a
|
|
71
|
+
* replay re-executes actions only, never the engine's systems.
|
|
72
|
+
*/
|
|
73
|
+
Replay: 'replay',
|
|
74
|
+
});
|
|
75
|
+
|
|
48
76
|
const DEFAULT_SIMULATION_DELAY_TICKS = 4;
|
|
49
77
|
const DEFAULT_INITIAL_RENDER_DELAY_FRAMES = 6;
|
|
50
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Frames of remote state the network timeline keeps at the least: the adaptive render delay's
|
|
81
|
+
* ceiling (30) plus room for the playhead to blend across a burst of late arrivals.
|
|
82
|
+
*/
|
|
83
|
+
const PLAYOUT_HISTORY_FRAMES = 64;
|
|
84
|
+
|
|
51
85
|
/**
|
|
52
86
|
* Default depth of the action-log ring (in frames). This single value bounds
|
|
53
87
|
* THREE distinct horizons at once:
|
|
@@ -66,8 +100,6 @@ const DEFAULT_INITIAL_RENDER_DELAY_FRAMES = 6;
|
|
|
66
100
|
* orchestrator, so it is cheap to grow).
|
|
67
101
|
*/
|
|
68
102
|
const DEFAULT_ACTION_LOG_FRAME_CAPACITY = 32;
|
|
69
|
-
const MAX_CLIENT_DILATED_TICKS_PER_STEP = 3;
|
|
70
|
-
const MAX_FIXED_STEPS_PER_TICK = 8;
|
|
71
103
|
|
|
72
104
|
const DEFAULT_SERVER_RESUME_GRACE_MS = 30_000;
|
|
73
105
|
/**
|
|
@@ -108,6 +140,19 @@ const ReconnectState = Object.freeze({
|
|
|
108
140
|
Lost: 'lost',
|
|
109
141
|
});
|
|
110
142
|
|
|
143
|
+
/**
|
|
144
|
+
* Client-side: how the host has answered the transport binding in use. A new binding does not know
|
|
145
|
+
* which world the client is in until the host says: the one it has been predicting on, which the
|
|
146
|
+
* host resumes (RESUME_ACCEPT), or the host's own, sent as a snapshot (INITIAL_SYNC). The first
|
|
147
|
+
* answer is the answer; the host's handshake arriving after it is stale.
|
|
148
|
+
* @readonly @enum {string}
|
|
149
|
+
*/
|
|
150
|
+
const BindingAnswer = Object.freeze({
|
|
151
|
+
Pending: 'pending',
|
|
152
|
+
Resumed: 'resumed',
|
|
153
|
+
Synced: 'synced',
|
|
154
|
+
});
|
|
155
|
+
|
|
111
156
|
/**
|
|
112
157
|
* Scratch buffer size used for AUTH_STATE assembly and net_mutate_component
|
|
113
158
|
* event payloads. Sized for the common cases (Transform ≈ 36 B); components
|
|
@@ -115,12 +160,92 @@ const ReconnectState = Object.freeze({
|
|
|
115
160
|
*/
|
|
116
161
|
const SCRATCH_BUFFER_BYTES = 1024;
|
|
117
162
|
|
|
163
|
+
|
|
118
164
|
/**
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
* @type {Uint8Array}
|
|
165
|
+
* {@link NetworkSession#tick} warns once per process.
|
|
166
|
+
* @type {boolean}
|
|
122
167
|
*/
|
|
123
|
-
|
|
168
|
+
let tick_deprecation_warned = false;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* The deprecated {@link NetworkSession#replicate} warns once per process.
|
|
172
|
+
* @type {boolean}
|
|
173
|
+
*/
|
|
174
|
+
let replicate_deprecation_warned = false;
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* @param {string} method for the message
|
|
178
|
+
* @param {string} name the component's, for the message
|
|
179
|
+
* @param {*} adapter the blend
|
|
180
|
+
*/
|
|
181
|
+
function assert_linear_blend(method, name, adapter) {
|
|
182
|
+
if (!(adapter instanceof BinaryInterpolationAdapter)) {
|
|
183
|
+
throw new Error(`NetworkSession.${method}: the blend for ${name} must extend BinaryInterpolationAdapter`);
|
|
184
|
+
}
|
|
185
|
+
if (adapter.kind !== InterpolationKind.Linear) {
|
|
186
|
+
throw new Error(
|
|
187
|
+
`NetworkSession.${method}: only Linear interpolation is currently supported; got kind=${adapter.kind} for ${name}. ` +
|
|
188
|
+
`A component with no in-between is replicated with replicate_discrete(); Cubic is reserved.`,
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* @param {string} method for the message
|
|
195
|
+
* @param {string} name the component's, for the message
|
|
196
|
+
* @param {*} correction
|
|
197
|
+
*/
|
|
198
|
+
function assert_correction(method, name, correction) {
|
|
199
|
+
if (correction === null || correction === undefined || correction.isCorrection !== true) {
|
|
200
|
+
throw new Error(
|
|
201
|
+
`NetworkSession.${method}: ${name} needs a Correction — how a client that predicts it corrects it when the host disagrees ` +
|
|
202
|
+
`(HOST_VALUE_CORRECTION takes the host's value)`,
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* While a blend is drawn over a component, its simulated value is held aside and put back before the
|
|
209
|
+
* next step. Held through a wire layout it would come back rounded, every step, and small increments
|
|
210
|
+
* would drift or stall; held with the component's own `copy`, it comes back exactly.
|
|
211
|
+
*
|
|
212
|
+
* @param {string} method for the message
|
|
213
|
+
* @param {string} name the component's, for the message
|
|
214
|
+
* @param {Function} ComponentClass
|
|
215
|
+
*/
|
|
216
|
+
function assert_copies_itself(method, name, ComponentClass) {
|
|
217
|
+
if (typeof ComponentClass.prototype.copy !== 'function') {
|
|
218
|
+
throw new Error(
|
|
219
|
+
`NetworkSession.${method}: ${name} is blended between network ticks, and while a blend is drawn over it the engine holds ` +
|
|
220
|
+
`its simulated value with ${name}.prototype.copy(other), which it does not have. Give ${name} a copy(other) that copies every ` +
|
|
221
|
+
`field the simulation uses, or replicate it with replicate_discrete().`,
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* @param {Uint8Array} a
|
|
228
|
+
* @param {Uint8Array} b
|
|
229
|
+
* @param {number} length
|
|
230
|
+
* @returns {boolean}
|
|
231
|
+
*/
|
|
232
|
+
function bytes_equal(a, b, length) {
|
|
233
|
+
for (let i = 0; i < length; i++) {
|
|
234
|
+
if (a[i] !== b[i]) return false;
|
|
235
|
+
}
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* @param {Uint8Array} a
|
|
241
|
+
* @param {number} a_length
|
|
242
|
+
* @param {Uint8Array} b
|
|
243
|
+
* @param {number} b_length
|
|
244
|
+
* @returns {boolean}
|
|
245
|
+
*/
|
|
246
|
+
function bytes_equal_lengths(a, a_length, b, b_length) {
|
|
247
|
+
return a_length === b_length && bytes_equal(a, b, a_length);
|
|
248
|
+
}
|
|
124
249
|
|
|
125
250
|
/**
|
|
126
251
|
* High-level networking facade. Wraps the orchestrator + state machinery
|
|
@@ -133,23 +258,45 @@ const EMPTY_PAYLOAD = new Uint8Array(0);
|
|
|
133
258
|
* Mutation is event-driven: callers fire
|
|
134
259
|
* `dataset.sendEvent(entity, "net_mutate_component", payload)`.
|
|
135
260
|
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
261
|
+
* **The session runs on the engine's clock.** The `EntityManager`'s fixed
|
|
262
|
+
* step is the network tick: each step opens a network frame before any
|
|
263
|
+
* system's `fixedUpdate` and closes it after the last, so everything the
|
|
264
|
+
* step simulates — physics, controllers, game code — happens inside the
|
|
265
|
+
* frame. There is nothing to call per frame; `entity_manager.update(dt)`
|
|
266
|
+
* (the engine loop) drives it. Client time dilation is applied as the
|
|
267
|
+
* `EntityManager`'s `fixedStepTimeScale`.
|
|
268
|
+
*
|
|
269
|
+
* What arrives from the network is applied as a step opens, never when the
|
|
270
|
+
* transport happens to deliver it: a browser delivers packets whenever its
|
|
271
|
+
* event loop gets to them, which is usually between a frame's render blend and
|
|
272
|
+
* its draw. And the session's timers — the render playout, idle reaping, the
|
|
273
|
+
* grace window — run on the frame time the engine passes to `update`, so they
|
|
274
|
+
* pause with the engine and follow any engine that is driven by hand.
|
|
275
|
+
*
|
|
276
|
+
* **Networked entities are smooth by default.** The session attaches an
|
|
277
|
+
* {@link Interpolated} to each one and keeps it in line with ownership: on
|
|
278
|
+
* the host, and for entities the client owns (and predicts), the local
|
|
279
|
+
* fixed-step timeline; for everything else on a client, the network's
|
|
280
|
+
* render-delayed playout. Both are blended by the engine's
|
|
281
|
+
* {@link InterpolationSystem}, which the session adds if the engine has
|
|
282
|
+
* none.
|
|
140
283
|
*
|
|
141
284
|
* @author Alex Goldring
|
|
142
285
|
* @copyright Company Named Limited (c) 2026
|
|
143
286
|
*/
|
|
144
287
|
export class NetworkSession {
|
|
145
288
|
|
|
146
|
-
// ---- Pre-start registration (
|
|
289
|
+
// ---- Pre-start registration (replicate_* / defineAction / defineInputSampler) ----
|
|
147
290
|
|
|
148
291
|
/**
|
|
149
|
-
* User-registered replicated component classes, in
|
|
150
|
-
*
|
|
151
|
-
* `NetworkIdentity` prepended.
|
|
152
|
-
*
|
|
292
|
+
* User-registered replicated component classes, in the order they were
|
|
293
|
+
* registered. Finalized at `start()` into {@link #replicated} with
|
|
294
|
+
* `NetworkIdentity` prepended. `interpoland` is how the component is blended
|
|
295
|
+
* between network ticks, `null` when it is not; `interpolator` is the blend
|
|
296
|
+
* handed to the deprecated {@link replicate}, turned into an interpoland at
|
|
297
|
+
* `start()`, when the component's replication layout is known; `correction`
|
|
298
|
+
* is how a client corrects it.
|
|
299
|
+
* @private @type {Array<{klass: Function, interpoland: Interpoland|null, interpolator: BinaryInterpolationAdapter|null, correction: Correction}>}
|
|
153
300
|
*/
|
|
154
301
|
#user_replicated = [];
|
|
155
302
|
|
|
@@ -157,8 +304,8 @@ export class NetworkSession {
|
|
|
157
304
|
* Finalized at `start()`. Insertion order = wire-format order;
|
|
158
305
|
* `NetworkIdentity` is the first entry (its slot allocation must
|
|
159
306
|
* fire before subsequent components attach during initial-sync apply).
|
|
160
|
-
*
|
|
161
|
-
* @private @type {Map<Function, {
|
|
307
|
+
* `interp_type_id` is the component's replication type id.
|
|
308
|
+
* @private @type {Map<Function, {interp_type_id: number, interpoland: Interpoland|null, interpolator: BinaryInterpolationAdapter|null, correction: Correction|null}>}
|
|
162
309
|
*/
|
|
163
310
|
#replicated = new Map();
|
|
164
311
|
|
|
@@ -215,19 +362,145 @@ export class NetworkSession {
|
|
|
215
362
|
#playout;
|
|
216
363
|
|
|
217
364
|
/**
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
* polluted (smooth) when true.
|
|
222
|
-
* @private @type {boolean}
|
|
365
|
+
* @deprecated Always false. Render blends are owned by the {@link InterpolationSystem}, which
|
|
366
|
+
* restores them itself; {@link normalize_if_dirty} restores unconditionally.
|
|
367
|
+
* @type {boolean}
|
|
223
368
|
*/
|
|
224
369
|
render_dirty = false;
|
|
225
370
|
|
|
371
|
+
// ---- Interpolation wiring (set in start()) ----
|
|
372
|
+
|
|
373
|
+
/** @private @type {InterpolationSystem|null} */
|
|
374
|
+
#interpolation = null;
|
|
375
|
+
|
|
376
|
+
/** @private @type {number} source id of the network playout in {@link #interpolation} */
|
|
377
|
+
#interp_source_id = -1;
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Interpolands for the replicated components that interpolate, in `#replicated` order. The
|
|
381
|
+
* same list serves both timelines: records on the local timeline are keyed by entity, records
|
|
382
|
+
* in the network log by `network_id`.
|
|
383
|
+
* @private @type {Interpoland[]}
|
|
384
|
+
*/
|
|
385
|
+
#interpolands = [];
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Networked entities whose {@link Interpolated} has to be brought in line with their role —
|
|
389
|
+
* newly networked, or ownership changed. Applied as the next step opens, not from inside the
|
|
390
|
+
* observer that noticed: on an initial sync the identity arrives before the components it
|
|
391
|
+
* would interpolate.
|
|
392
|
+
* @private @type {Set<number>}
|
|
393
|
+
*/
|
|
394
|
+
#interpolation_pending = new Set();
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* The {@link Interpolated} components this session attached, by entity, so it can take them
|
|
398
|
+
* back.
|
|
399
|
+
* @private @type {Map<number, Interpolated>}
|
|
400
|
+
*/
|
|
401
|
+
#attached_interpolated = new Map();
|
|
402
|
+
|
|
403
|
+
/** @private @type {{tick_a:number, tick_b:number, t:number}} */
|
|
404
|
+
#playout_window = { tick_a: 0, tick_b: 0, t: 0 };
|
|
405
|
+
|
|
226
406
|
// ---- Per-tick driver state ----
|
|
227
407
|
|
|
228
408
|
/** @private @type {number} */ #local_frame = 0;
|
|
229
|
-
|
|
230
|
-
/** @private @type {
|
|
409
|
+
|
|
410
|
+
/** @private @type {boolean} a network frame is open: the fixed step that opened it has not closed */
|
|
411
|
+
#step_open = false;
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Every connected peer's transport, holding what arrives until the next fixed step opens.
|
|
415
|
+
* @private @type {Map<number, DeferredTransport>}
|
|
416
|
+
*/
|
|
417
|
+
#inbound = new Map();
|
|
418
|
+
|
|
419
|
+
// ---- Host: publishing what the simulation changed ----
|
|
420
|
+
|
|
421
|
+
/** @private @type {boolean} */
|
|
422
|
+
#publish_changes;
|
|
423
|
+
|
|
424
|
+
/** @private @type {string} */
|
|
425
|
+
#late_input;
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* What the peers hold for each networked entity, per replicated component type id, as the
|
|
429
|
+
* replication adapter's bytes — so "changed" means "changed on the wire". Updated by every
|
|
430
|
+
* record the host publishes and by every action it executes (the peers apply the action and
|
|
431
|
+
* arrive at the same value), and compared with the live state at the end of each step.
|
|
432
|
+
* @private @type {Map<number, Array<{bytes: Uint8Array, length: number}|null>>}
|
|
433
|
+
*/
|
|
434
|
+
#published = new Map();
|
|
435
|
+
|
|
436
|
+
/** @private @type {BinaryBuffer} */
|
|
437
|
+
#scratch_publish_buf = new BinaryBuffer();
|
|
438
|
+
|
|
439
|
+
// ---- Client: reconciliation by comparison ----
|
|
440
|
+
|
|
441
|
+
/** @private @type {string} */
|
|
442
|
+
#reconcile;
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* What this client predicted for the entities it owns, per frame, as wire bytes.
|
|
446
|
+
* @private @type {PredictionHistory}
|
|
447
|
+
*/
|
|
448
|
+
#prediction_history = new PredictionHistory(128);
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Authoritative states waiting for the next step, newest per network id: the frame and each
|
|
452
|
+
* replicated component's bytes, in `#replicated` order (`null` where the entity lacks it).
|
|
453
|
+
* @private @type {Map<number, {frame: number, parts: Array<{type_id: number, bytes: Uint8Array}|null>}>}
|
|
454
|
+
*/
|
|
455
|
+
#pending_auth = new Map();
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* The newest frame reconciled per network id. An authoritative state for that frame or an
|
|
459
|
+
* earlier one arriving afterwards — reordered, or retransmitted — is stale: the present was
|
|
460
|
+
* already moved by a newer one, and moving it again by an older difference would undo that.
|
|
461
|
+
* @private @type {Map<number, number>}
|
|
462
|
+
*/
|
|
463
|
+
#reconciled_frame = new Map();
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Scratch instances per replicated class, for decoding without touching the world: the host's
|
|
467
|
+
* state, the prediction, and a later prediction being corrected.
|
|
468
|
+
* @private @type {Map<Function, object[]>}
|
|
469
|
+
*/
|
|
470
|
+
#decode_scratch = new Map();
|
|
471
|
+
|
|
472
|
+
/** @private @type {CorrectionTarget} */
|
|
473
|
+
#correction_target = new CorrectionTarget();
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Per replicated component, in `#replicated` order: whether the one being reconciled differs.
|
|
477
|
+
* @private @type {boolean[]}
|
|
478
|
+
*/
|
|
479
|
+
#differs = [];
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Client: authoritative states that differed from the prediction and were corrected.
|
|
483
|
+
* @type {number}
|
|
484
|
+
*/
|
|
485
|
+
correction_count = 0;
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Client: authoritative states that could not be compared because the prediction for their
|
|
489
|
+
* frame is not held (before the first predicted frame, or older than the history).
|
|
490
|
+
* @type {number}
|
|
491
|
+
*/
|
|
492
|
+
correction_skipped_count = 0;
|
|
493
|
+
|
|
494
|
+
/**
|
|
495
|
+
* Client, {@link NetworkSessionReconcile.Correct}: a component of an authoritative state
|
|
496
|
+
* differed from the prediction, and the present was corrected. Once per component corrected.
|
|
497
|
+
* Args: `(entity_id, server_frame, component_class, magnitude)` — the size of the correction as
|
|
498
|
+
* the component's {@link Correction} measures it (a pose: how far the position moved, in world
|
|
499
|
+
* units). Diagnostic: a steady stream of these on a quiet link means the client simulates
|
|
500
|
+
* something differently from the host.
|
|
501
|
+
* @type {Signal}
|
|
502
|
+
*/
|
|
503
|
+
onCorrection = new Signal();
|
|
231
504
|
|
|
232
505
|
/** @private @type {Set<number>} */
|
|
233
506
|
#connected_peers = new Set();
|
|
@@ -235,12 +508,28 @@ export class NetworkSession {
|
|
|
235
508
|
/**
|
|
236
509
|
* Host-only: peer_id → remaining-resends. Drained in
|
|
237
510
|
* `#on_host_tick_complete` once `current_sim_frame >= 0`. Sent twice
|
|
238
|
-
* for loss tolerance
|
|
239
|
-
*
|
|
511
|
+
* for loss tolerance, and never queued again on the peer's say-so: each
|
|
512
|
+
* send serializes the whole world, and a sync the peer could ask for is one
|
|
513
|
+
* it could keep asking for. Filled only by {@link #queue_initial_sync}.
|
|
514
|
+
* (A fragment of one that goes missing is re-sent on the receiver's
|
|
515
|
+
* NACK_FRAGMENT. That repair is `NetworkPeer`'s: a NACK re-sends each
|
|
516
|
+
* chunk of the sync at most once, for at most
|
|
517
|
+
* `FRAGMENT_RETENTION_MAX_RETRIES` NACKs, so it adds at most that many
|
|
518
|
+
* copies of each sync, however the peer asks.)
|
|
240
519
|
* @private @type {Map<number, number>}
|
|
241
520
|
*/
|
|
242
521
|
#pending_initial_sync = new Map();
|
|
243
522
|
|
|
523
|
+
/**
|
|
524
|
+
* Host-only: peers whose current connection has been given its
|
|
525
|
+
* INITIAL_SYNC — queued, or queued and already sent. A connection is
|
|
526
|
+
* given the world once. Cleared when `connect()` binds the peer a new
|
|
527
|
+
* connection; until then it describes the last one, on which nothing can
|
|
528
|
+
* arrive any more.
|
|
529
|
+
* @private @type {Set<number>}
|
|
530
|
+
*/
|
|
531
|
+
#initial_sync_given = new Set();
|
|
532
|
+
|
|
244
533
|
/**
|
|
245
534
|
* Sampled-action ledger for predict-reconcile replay. The sampler
|
|
246
535
|
* reads live input, so re-calling it during reconcile would give
|
|
@@ -270,6 +559,15 @@ export class NetworkSession {
|
|
|
270
559
|
*/
|
|
271
560
|
#peer_grace_state = new Map();
|
|
272
561
|
|
|
562
|
+
/**
|
|
563
|
+
* Peers whose current connection has had its RESUME_HELLO answered. A
|
|
564
|
+
* client sends at most one per connection, from `connect()`; the host
|
|
565
|
+
* answers the first and ignores the rest. Cleared when `connect()` binds
|
|
566
|
+
* the peer a new connection.
|
|
567
|
+
* @private @type {Set<number>}
|
|
568
|
+
*/
|
|
569
|
+
#resume_hello_answered = new Set();
|
|
570
|
+
|
|
273
571
|
/**
|
|
274
572
|
* Per-peer transport onDisconnect listener bookkeeping so we can
|
|
275
573
|
* unsubscribe when the peer is fully dropped.
|
|
@@ -312,6 +610,26 @@ export class NetworkSession {
|
|
|
312
610
|
* @private @type {boolean}
|
|
313
611
|
*/
|
|
314
612
|
#has_ever_connected = false;
|
|
613
|
+
/**
|
|
614
|
+
* Client-side: how the host has answered the binding the last `connect()`
|
|
615
|
+
* made. Once it has, what the binding carries about the handshake is news
|
|
616
|
+
* no longer: the host sends each sync more than once against loss, and a
|
|
617
|
+
* host that has finished with our old session takes the new transport for
|
|
618
|
+
* a fresh peer and sends its sync before reading the RESUME_HELLO the
|
|
619
|
+
* transport carried, so the RESUME_REJECT it answers that with arrives
|
|
620
|
+
* after the resync it asks for.
|
|
621
|
+
* @private @type {BindingAnswer|string}
|
|
622
|
+
*/
|
|
623
|
+
#binding_answer = BindingAnswer.Pending;
|
|
624
|
+
/**
|
|
625
|
+
* Client-side: the first frame predicted on the world this client holds —
|
|
626
|
+
* where the last INITIAL_SYNC it applied set the frame counter, 0 before
|
|
627
|
+
* any. Input predicted before it was predicted on a world the sync
|
|
628
|
+
* replaced, and is never sent: not by the binding that brought the sync,
|
|
629
|
+
* and not by any later one that resumes the world the sync began.
|
|
630
|
+
* @private @type {number}
|
|
631
|
+
*/
|
|
632
|
+
#world_start_frame = 0;
|
|
315
633
|
|
|
316
634
|
// ---- Signals (initialized inline because they take no input) ----
|
|
317
635
|
|
|
@@ -376,7 +694,13 @@ export class NetworkSession {
|
|
|
376
694
|
/** @private @type {(() => object) | null} */ #transport_factory;
|
|
377
695
|
|
|
378
696
|
/** @private @type {number} ms of inbound silence before reaping; 0 = off */ #connection_timeout_ms;
|
|
379
|
-
/**
|
|
697
|
+
/**
|
|
698
|
+
* The session's clock, in milliseconds: the engine's frame time, advanced by the delta of every
|
|
699
|
+
* rendered frame. Paces the render playout, idle reaping and the grace window, so all of them
|
|
700
|
+
* follow the engine — a paused engine pauses them, a test that drives the engine drives them.
|
|
701
|
+
* @private @type {number}
|
|
702
|
+
*/
|
|
703
|
+
#clock_ms = 0;
|
|
380
704
|
/**
|
|
381
705
|
* Per-peer liveness mark: the inbound-packet count last seen and the clock
|
|
382
706
|
* time it was last seen advancing. Drives idle reaping.
|
|
@@ -421,7 +745,10 @@ export class NetworkSession {
|
|
|
421
745
|
* unique across peers.
|
|
422
746
|
* - `simulation_delay_ticks` is honored only under `role: 'host'`.
|
|
423
747
|
* Default 4. See {@link ServerAuthoritativeServer}.
|
|
424
|
-
* - `tick_rate_hz
|
|
748
|
+
* - `tick_rate_hz`: the network tick rate, which is the engine's fixed-step
|
|
749
|
+
* rate — given, it sets `entity_manager.fixedUpdateStepSize`; omitted, the
|
|
750
|
+
* session uses the step the engine already has (60 Hz by default). Every
|
|
751
|
+
* peer must run the same rate.
|
|
425
752
|
* - `frame_capacity` sizes the action-log ring (rollback depth + back-fill
|
|
426
753
|
* range + retransmit window — see {@link DEFAULT_ACTION_LOG_FRAME_CAPACITY}).
|
|
427
754
|
* Default 32. Raise it for high-RTT / lossy links.
|
|
@@ -435,6 +762,18 @@ export class NetworkSession {
|
|
|
435
762
|
* - `reconnect` (client role): policy for the reconnect ladder. See
|
|
436
763
|
* {@link DEFAULT_RECONNECT_POLICY}. Set `enabled: false` to opt
|
|
437
764
|
* out entirely.
|
|
765
|
+
* - `publish_changes` (host role, default true): at the end of every
|
|
766
|
+
* step, send each replicated component the simulation changed — physics,
|
|
767
|
+
* controllers, anything that wrote it directly. Components an action
|
|
768
|
+
* wrote are already on the wire and are not sent twice. Publishing never
|
|
769
|
+
* writes back into the host's own state. Set false to publish by hand
|
|
770
|
+
* (`net_mutate_component`).
|
|
771
|
+
* - `reconcile` (client role): see {@link NetworkSessionReconcile}. Default
|
|
772
|
+
* `'correct'`.
|
|
773
|
+
* - `late_input` (host role): what to do with client input that arrives
|
|
774
|
+
* for a frame already simulated — see {@link LateInput}. Default
|
|
775
|
+
* `'apply'`: fold it into the current frame. `'rollback'` rewinds and
|
|
776
|
+
* replays, which re-executes actions only, never the engine's systems.
|
|
438
777
|
*/
|
|
439
778
|
constructor({
|
|
440
779
|
entity_manager,
|
|
@@ -443,7 +782,7 @@ export class NetworkSession {
|
|
|
443
782
|
role = NetworkSessionRole.Client,
|
|
444
783
|
local_peer_id = -1,
|
|
445
784
|
simulation_delay_ticks = DEFAULT_SIMULATION_DELAY_TICKS,
|
|
446
|
-
tick_rate_hz =
|
|
785
|
+
tick_rate_hz = undefined,
|
|
447
786
|
frame_capacity = DEFAULT_ACTION_LOG_FRAME_CAPACITY,
|
|
448
787
|
binary_registry = null,
|
|
449
788
|
scope_filter = null,
|
|
@@ -452,14 +791,19 @@ export class NetworkSession {
|
|
|
452
791
|
server_resume_grace_ms = DEFAULT_SERVER_RESUME_GRACE_MS,
|
|
453
792
|
connection_timeout_ms = DEFAULT_CONNECTION_TIMEOUT_MS,
|
|
454
793
|
reconnect = null,
|
|
794
|
+
publish_changes = true,
|
|
795
|
+
late_input = LateInput.Apply,
|
|
796
|
+
reconcile = NetworkSessionReconcile.Correct,
|
|
455
797
|
} = {}) {
|
|
456
798
|
assert.ok(entity_manager !== undefined && entity_manager !== null,
|
|
457
799
|
'NetworkSession: entity_manager is required');
|
|
458
800
|
if (role !== NetworkSessionRole.Client && role !== NetworkSessionRole.Host) {
|
|
459
801
|
throw new Error(`NetworkSession: invalid role '${role}'`);
|
|
460
802
|
}
|
|
461
|
-
|
|
462
|
-
|
|
803
|
+
if (tick_rate_hz !== undefined) {
|
|
804
|
+
assert.isNumber(tick_rate_hz, 'tick_rate_hz');
|
|
805
|
+
assert.ok(tick_rate_hz > 0, 'tick_rate_hz must be positive');
|
|
806
|
+
}
|
|
463
807
|
assert.isNonNegativeInteger(simulation_delay_ticks, 'simulation_delay_ticks');
|
|
464
808
|
assert.isPositiveInteger(frame_capacity, 'frame_capacity');
|
|
465
809
|
|
|
@@ -481,11 +825,18 @@ export class NetworkSession {
|
|
|
481
825
|
*/
|
|
482
826
|
this.role = role;
|
|
483
827
|
|
|
828
|
+
// One clock: the network tick IS the engine's fixed step. A rate given here sets the step;
|
|
829
|
+
// otherwise the session adopts the one the engine already has.
|
|
830
|
+
if (tick_rate_hz !== undefined) {
|
|
831
|
+
entity_manager.fixedUpdateStepSize = 1 / tick_rate_hz;
|
|
832
|
+
}
|
|
833
|
+
|
|
484
834
|
/**
|
|
835
|
+
* The network tick period, which is the `EntityManager`'s fixed step.
|
|
485
836
|
* @readonly
|
|
486
837
|
* @type {number}
|
|
487
838
|
*/
|
|
488
|
-
this.tick_period_ms =
|
|
839
|
+
this.tick_period_ms = entity_manager.fixedUpdateStepSize * 1000;
|
|
489
840
|
|
|
490
841
|
/**
|
|
491
842
|
* @readonly
|
|
@@ -553,6 +904,12 @@ export class NetworkSession {
|
|
|
553
904
|
this.#connection_timeout_ms = connection_timeout_ms;
|
|
554
905
|
this.#reconnect_policy = Object.freeze({ ...DEFAULT_RECONNECT_POLICY, ...(reconnect || {}) });
|
|
555
906
|
this.#transport_factory = transport_factory;
|
|
907
|
+
this.#publish_changes = publish_changes;
|
|
908
|
+
this.#late_input = late_input;
|
|
909
|
+
if (reconcile !== NetworkSessionReconcile.Correct && reconcile !== NetworkSessionReconcile.Replay) {
|
|
910
|
+
throw new Error(`NetworkSession: reconcile must be one of ${Object.values(NetworkSessionReconcile).join(', ')}, got '${reconcile}'`);
|
|
911
|
+
}
|
|
912
|
+
this.#reconcile = reconcile;
|
|
556
913
|
}
|
|
557
914
|
|
|
558
915
|
// ----------------------------------------------------------------
|
|
@@ -560,52 +917,129 @@ export class NetworkSession {
|
|
|
560
917
|
// ----------------------------------------------------------------
|
|
561
918
|
|
|
562
919
|
/**
|
|
563
|
-
*
|
|
920
|
+
* Replicate `ComponentClass`, and draw it between network ticks by blending. A network tick is
|
|
921
|
+
* coarser than a rendered frame, and a component shown only as each state lands moves in steps;
|
|
922
|
+
* `interpoland` says how it is drawn instead — the layout each tick's state is recorded in, and
|
|
923
|
+
* the blend of two records for a rendered frame.
|
|
924
|
+
*
|
|
925
|
+
* - `interpoland.component_class` is `ComponentClass`, and its blend is of kind
|
|
926
|
+
* {@link InterpolationKind.Linear}.
|
|
927
|
+
* - `interpoland.type_id` names its records. No two components one session replicates may share
|
|
928
|
+
* one; {@link start} checks.
|
|
929
|
+
* - `ComponentClass` has `copy(other)`: while a blend is drawn over the component, its simulated
|
|
930
|
+
* value is held with it, and put back exactly before the next step.
|
|
931
|
+
*
|
|
932
|
+
* `correction` is how a client that predicts the component corrects it when the host disagrees
|
|
933
|
+
* — see {@link Correction}.
|
|
934
|
+
*
|
|
935
|
+
* See {@link replicate_discrete} for a component with no in-between.
|
|
936
|
+
*
|
|
937
|
+
* Like every replicated component, `ComponentClass` needs a
|
|
938
|
+
* {@link BinaryClassSerializationAdapter} registered for its `typeName` in `binary_registry`
|
|
939
|
+
* before {@link start} — its wire format. Components are laid out on the wire in the order they
|
|
940
|
+
* are replicated, so every peer must replicate the same components in the same order.
|
|
941
|
+
*
|
|
942
|
+
* @param {Function} ComponentClass
|
|
943
|
+
* @param {Interpoland} interpoland
|
|
944
|
+
* @param {Correction} correction
|
|
945
|
+
*/
|
|
946
|
+
replicate_interpolated(ComponentClass, interpoland, correction) {
|
|
947
|
+
const name = this.#assert_can_replicate('replicate_interpolated', ComponentClass);
|
|
948
|
+
|
|
949
|
+
if (interpoland === null || interpoland === undefined || interpoland.isInterpoland !== true) {
|
|
950
|
+
throw new Error(`NetworkSession.replicate_interpolated: ${name} needs an Interpoland — the layout its states are recorded in, and the blend between them`);
|
|
951
|
+
}
|
|
952
|
+
if (interpoland.component_class !== ComponentClass) {
|
|
953
|
+
throw new Error(`NetworkSession.replicate_interpolated: the interpoland given for ${name} interpolates ${interpoland.component_class?.typeName ?? interpoland.component_class?.name}`);
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
assert_linear_blend('replicate_interpolated', name, interpoland.interpolation_adapter);
|
|
957
|
+
assert_copies_itself('replicate_interpolated', name, ComponentClass);
|
|
958
|
+
assert_correction('replicate_interpolated', name, correction);
|
|
959
|
+
|
|
960
|
+
this.#user_replicated.push({ klass: ComponentClass, interpoland, interpolator: null, correction });
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
/**
|
|
964
|
+
* Replicate `ComponentClass`, and draw it as each state lands, with no blend between network
|
|
965
|
+
* ticks. For a value that has no in-between — a count, a name, a state machine's state.
|
|
564
966
|
*
|
|
565
|
-
*
|
|
566
|
-
*
|
|
567
|
-
* before {@link start} is called — that adapter handles the wire
|
|
568
|
-
* format and rewind capture.
|
|
967
|
+
* `correction` is how a client that predicts the component corrects it when the host disagrees
|
|
968
|
+
* — see {@link Correction}.
|
|
569
969
|
*
|
|
570
|
-
*
|
|
571
|
-
*
|
|
572
|
-
*
|
|
573
|
-
*
|
|
574
|
-
* reserved for future support and currently throw.
|
|
970
|
+
* Like every replicated component, `ComponentClass` needs a
|
|
971
|
+
* {@link BinaryClassSerializationAdapter} registered for its `typeName` in `binary_registry`
|
|
972
|
+
* before {@link start} — its wire format. Components are laid out on the wire in the order they
|
|
973
|
+
* are replicated, so every peer must replicate the same components in the same order.
|
|
575
974
|
*
|
|
576
|
-
*
|
|
577
|
-
*
|
|
578
|
-
|
|
975
|
+
* @param {Function} ComponentClass
|
|
976
|
+
* @param {Correction} correction
|
|
977
|
+
*/
|
|
978
|
+
replicate_discrete(ComponentClass, correction) {
|
|
979
|
+
const name = this.#assert_can_replicate('replicate_discrete', ComponentClass);
|
|
980
|
+
|
|
981
|
+
assert_correction('replicate_discrete', name, correction);
|
|
982
|
+
|
|
983
|
+
this.#user_replicated.push({ klass: ComponentClass, interpoland: null, interpolator: null, correction });
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
/**
|
|
987
|
+
* **Deprecated.** Use {@link replicate_interpolated} or {@link replicate_discrete}, which say how
|
|
988
|
+
* the component is drawn. Warns once.
|
|
579
989
|
*
|
|
990
|
+
* Keeps its meaning: `replicate(C)` replicates `C` discretely; `replicate(C, interpolator)` blends
|
|
991
|
+
* it with `interpolator`, recorded in its replication layout. A component blended this way needs
|
|
992
|
+
* `copy(other)`, as with {@link replicate_interpolated}. A client corrects what it registers by
|
|
993
|
+
* taking the host's value ({@link HOST_VALUE_CORRECTION}).
|
|
994
|
+
*
|
|
995
|
+
* @deprecated
|
|
580
996
|
* @param {Function} ComponentClass
|
|
581
|
-
* @param {BinaryInterpolationAdapter} [interpolator]
|
|
997
|
+
* @param {BinaryInterpolationAdapter|null} [interpolator]
|
|
582
998
|
*/
|
|
583
999
|
replicate(ComponentClass, interpolator = null) {
|
|
584
|
-
|
|
1000
|
+
if (!replicate_deprecation_warned) {
|
|
1001
|
+
replicate_deprecation_warned = true;
|
|
1002
|
+
console.warn(
|
|
1003
|
+
'NetworkSession.replicate() is deprecated: use replicate_interpolated(C, interpoland, correction) for a component ' +
|
|
1004
|
+
'blended between network ticks, or replicate_discrete(C, correction) for one that is not.',
|
|
1005
|
+
);
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
if (interpolator === null) {
|
|
1009
|
+
this.replicate_discrete(ComponentClass, HOST_VALUE_CORRECTION);
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
const name = this.#assert_can_replicate('replicate', ComponentClass);
|
|
1014
|
+
|
|
1015
|
+
assert_linear_blend('replicate', name, interpolator);
|
|
1016
|
+
assert_copies_itself('replicate', name, ComponentClass);
|
|
1017
|
+
|
|
1018
|
+
this.#user_replicated.push({ klass: ComponentClass, interpoland: null, interpolator, correction: HOST_VALUE_CORRECTION });
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
/**
|
|
1022
|
+
* @param {string} method
|
|
1023
|
+
* @param {Function} ComponentClass
|
|
1024
|
+
* @returns {string} the component's name, for messages
|
|
1025
|
+
*/
|
|
1026
|
+
#assert_can_replicate(method, ComponentClass) {
|
|
1027
|
+
this.#assert_not_started(method);
|
|
585
1028
|
assert.isFunction(ComponentClass, 'ComponentClass');
|
|
586
1029
|
|
|
1030
|
+
const name = ComponentClass.typeName ?? ComponentClass.name;
|
|
1031
|
+
|
|
587
1032
|
if (ComponentClass === NetworkIdentity) {
|
|
588
|
-
throw new Error(
|
|
1033
|
+
throw new Error(`NetworkSession.${method}: NetworkIdentity is replicated by the session itself`);
|
|
589
1034
|
}
|
|
590
1035
|
|
|
591
1036
|
for (const entry of this.#user_replicated) {
|
|
592
1037
|
if (entry.klass === ComponentClass) {
|
|
593
|
-
throw new Error(`NetworkSession
|
|
1038
|
+
throw new Error(`NetworkSession.${method}: ${name} is already replicated`);
|
|
594
1039
|
}
|
|
595
1040
|
}
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
throw new Error("NetworkSession.replicate: interpolator must extend BinaryInterpolationAdapter");
|
|
599
|
-
}
|
|
600
|
-
if (interpolator.kind !== InterpolationKind.Linear) {
|
|
601
|
-
throw new Error(
|
|
602
|
-
`NetworkSession.replicate: only Linear interpolation is currently supported; ` +
|
|
603
|
-
`got kind=${interpolator.kind} for ${ComponentClass.typeName ?? ComponentClass.name}. ` +
|
|
604
|
-
`Omit the interpolator argument for snap (Discrete) behavior; Cubic is reserved.`,
|
|
605
|
-
);
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
this.#user_replicated.push({ klass: ComponentClass, interp: interpolator });
|
|
1041
|
+
|
|
1042
|
+
return name;
|
|
609
1043
|
}
|
|
610
1044
|
|
|
611
1045
|
/**
|
|
@@ -658,12 +1092,12 @@ export class NetworkSession {
|
|
|
658
1092
|
/**
|
|
659
1093
|
* Wire the session to the engine. After this, the EntityObserver
|
|
660
1094
|
* is active, the right orchestrator is constructed, and a
|
|
661
|
-
* {@link NetworkSystem} is attached. Subsequent
|
|
1095
|
+
* {@link NetworkSystem} is attached. Subsequent `replicate_*`
|
|
662
1096
|
* / {@link defineAction} / {@link defineInputSampler} calls throw.
|
|
663
1097
|
*
|
|
664
|
-
* Pre-condition: every component class
|
|
665
|
-
*
|
|
666
|
-
*
|
|
1098
|
+
* Pre-condition: every replicated component class must already have a
|
|
1099
|
+
* `BinaryClassSerializationAdapter` registered in the session's
|
|
1100
|
+
* binary_registry.
|
|
667
1101
|
*/
|
|
668
1102
|
async start() {
|
|
669
1103
|
if (this.#started) throw new Error("NetworkSession.start: already started");
|
|
@@ -684,13 +1118,15 @@ export class NetworkSession {
|
|
|
684
1118
|
const network_identity_scratch = new BinaryBuffer();
|
|
685
1119
|
network_identity_scratch.setCapacity(SCRATCH_BUFFER_BYTES);
|
|
686
1120
|
this.#replicated.set(NetworkIdentity, {
|
|
687
|
-
interp: null,
|
|
688
1121
|
interp_type_id: next_id++,
|
|
1122
|
+
interpoland: null,
|
|
1123
|
+
interpolator: null,
|
|
1124
|
+
correction: null, // ownership is never predicted
|
|
689
1125
|
});
|
|
690
1126
|
this.#interp_type_id_to_class[0] = NetworkIdentity;
|
|
691
|
-
for (const { klass,
|
|
1127
|
+
for (const { klass, interpoland, interpolator, correction } of this.#user_replicated) {
|
|
692
1128
|
const interp_type_id = next_id++;
|
|
693
|
-
this.#replicated.set(klass, {
|
|
1129
|
+
this.#replicated.set(klass, { interp_type_id, interpoland, interpolator, correction });
|
|
694
1130
|
this.#interp_type_id_to_class[interp_type_id] = klass;
|
|
695
1131
|
}
|
|
696
1132
|
|
|
@@ -705,6 +1141,8 @@ export class NetworkSession {
|
|
|
705
1141
|
}
|
|
706
1142
|
}
|
|
707
1143
|
|
|
1144
|
+
this.#interpolands = this.#build_interpolands();
|
|
1145
|
+
|
|
708
1146
|
// Build the synthetic ReplaceComponentAction now so it's in the
|
|
709
1147
|
// action_classes list when the orchestrator is constructed.
|
|
710
1148
|
this.#ReplaceComponentAction = this.#make_replace_component_action_class();
|
|
@@ -724,6 +1162,7 @@ export class NetworkSession {
|
|
|
724
1162
|
this.#server = new ServerAuthoritativeServer({
|
|
725
1163
|
...orchestrator_opts,
|
|
726
1164
|
simulation_delay_ticks: this.simulation_delay_ticks,
|
|
1165
|
+
late_input: this.#late_input,
|
|
727
1166
|
});
|
|
728
1167
|
this.#peer = this.#server.peer;
|
|
729
1168
|
this.#peer.replicator.scope_filter = this.#scope_filter || new OwnerAwareScope({
|
|
@@ -732,6 +1171,9 @@ export class NetworkSession {
|
|
|
732
1171
|
identity_class: NetworkIdentity,
|
|
733
1172
|
});
|
|
734
1173
|
this.#server.onTickComplete.add((sim_frame) => this.#on_host_tick_complete(sim_frame));
|
|
1174
|
+
if (this.#publish_changes) {
|
|
1175
|
+
this.#server.onBeforeTickClose.add(() => this.#publish_simulated_changes());
|
|
1176
|
+
}
|
|
735
1177
|
} else {
|
|
736
1178
|
// Client role: covers both "playing" (input sampler registered)
|
|
737
1179
|
// and "spectator" (no sampler — sampler-driven onPredict
|
|
@@ -740,7 +1182,13 @@ export class NetworkSession {
|
|
|
740
1182
|
this.#client = new ServerAuthoritativeClient({
|
|
741
1183
|
...orchestrator_opts,
|
|
742
1184
|
time_dilation: this.#time_dilation,
|
|
1185
|
+
auto_reconcile: this.#reconcile === NetworkSessionReconcile.Replay,
|
|
743
1186
|
});
|
|
1187
|
+
if (this.#reconcile === NetworkSessionReconcile.Correct) {
|
|
1188
|
+
this.#client.peer.onAuthState.add((_peer_id, server_frame, network_id, buffer) => {
|
|
1189
|
+
this.#queue_auth_state(server_frame, network_id, buffer);
|
|
1190
|
+
});
|
|
1191
|
+
}
|
|
744
1192
|
this.#peer = this.#client.peer;
|
|
745
1193
|
if (this.#scope_filter) {
|
|
746
1194
|
this.#peer.replicator.scope_filter = this.#scope_filter;
|
|
@@ -750,12 +1198,19 @@ export class NetworkSession {
|
|
|
750
1198
|
|
|
751
1199
|
// Install the canonical-form normalize hook on the executor.
|
|
752
1200
|
// Anything that calls executor.execute — predict apply, action-
|
|
753
|
-
// stream apply, reconcile replay — first
|
|
754
|
-
//
|
|
755
|
-
//
|
|
756
|
-
// component
|
|
1201
|
+
// stream apply, reconcile replay — first puts back any render
|
|
1202
|
+
// blend, so the prior state it captures is the truth. Idempotent:
|
|
1203
|
+
// cheap when nothing is blended, one compare + deserialize per
|
|
1204
|
+
// blended component on the first execute after a render pass.
|
|
757
1205
|
this.#peer.executor.before_execute = this.#bound_normalize_if_dirty;
|
|
758
1206
|
|
|
1207
|
+
if (this.role === NetworkSessionRole.Host && this.#publish_changes) {
|
|
1208
|
+
// an action carries its own change to the peers: what it wrote is what they will hold
|
|
1209
|
+
this.#peer.executor.on_component_written = (entity_id, component_class) => {
|
|
1210
|
+
this.#note_published(entity_id, component_class);
|
|
1211
|
+
};
|
|
1212
|
+
}
|
|
1213
|
+
|
|
759
1214
|
// Secure-by-default inbound authorization on the host: a remote client
|
|
760
1215
|
// may only mutate entities it owns (NetworkIdentity.owner_peer_id ===
|
|
761
1216
|
// sender); the authoritative server (sender === local_peer_id) may
|
|
@@ -776,14 +1231,30 @@ export class NetworkSession {
|
|
|
776
1231
|
// startup completes (it auto-starts when added to an already-Running
|
|
777
1232
|
// EM). Await it so the session's identity observer below doesn't
|
|
778
1233
|
// race with the NetworkSystem's observer over slot_table allocation.
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
//
|
|
782
|
-
|
|
1234
|
+
//
|
|
1235
|
+
// It is also the session's place in the engine loop: each fixed step opens a network frame
|
|
1236
|
+
// and closes it, and every rendered frame runs the session's wall-paced work.
|
|
1237
|
+
await this.entity_manager.addSystem(new NetworkSystem(this.#peer, {
|
|
1238
|
+
open_step: () => this.#open_step(),
|
|
1239
|
+
close_step: () => this.#close_step(),
|
|
1240
|
+
frame: (dt) => this.#on_frame(dt),
|
|
1241
|
+
}));
|
|
1242
|
+
|
|
1243
|
+
// The network timeline: per-frame state of every remote entity, blended at render time on
|
|
1244
|
+
// the render-delayed playout by the engine's InterpolationSystem.
|
|
783
1245
|
this.#interp_log = new InterpolationLog({
|
|
784
|
-
buffer_capacity_bytes:
|
|
785
|
-
records_capacity:
|
|
786
|
-
});
|
|
1246
|
+
buffer_capacity_bytes: 1 << 18,
|
|
1247
|
+
records_capacity: 8192,
|
|
1248
|
+
}); // grows with the entity count, see #on_frame_applied
|
|
1249
|
+
|
|
1250
|
+
let interpolation = this.entity_manager.getSystem(InterpolationSystem);
|
|
1251
|
+
if (interpolation === null) {
|
|
1252
|
+
interpolation = new InterpolationSystem();
|
|
1253
|
+
await this.entity_manager.addSystem(interpolation);
|
|
1254
|
+
}
|
|
1255
|
+
this.#interpolation = interpolation;
|
|
1256
|
+
this.#interp_source_id = interpolation.allocateSourceId();
|
|
1257
|
+
interpolation.registerSource(this.#interp_source_id, this.#interp_log, () => this.#sample_playout());
|
|
787
1258
|
|
|
788
1259
|
// Per-frame applied: snapshot all replicated components for each
|
|
789
1260
|
// remote-owned entity into the interpolation log.
|
|
@@ -796,7 +1267,15 @@ export class NetworkSession {
|
|
|
796
1267
|
// action-stream processing, and finalize any in-flight Tier-3
|
|
797
1268
|
// resync state.
|
|
798
1269
|
if (this.role === NetworkSessionRole.Client) {
|
|
799
|
-
this.#peer.onInitialSync.add((
|
|
1270
|
+
this.#peer.onInitialSync.add((peer_id, session_token, frame_number, buf, payload_end) => {
|
|
1271
|
+
if (this.#binding_answer === BindingAnswer.Synced && this.#reconnect_state !== ReconnectState.Resyncing) {
|
|
1272
|
+
// A copy: the host sends every sync more than once, against loss, and this
|
|
1273
|
+
// binding already has its world. The client has been predicting on it since;
|
|
1274
|
+
// applied again, it would put what the client owns back behind input already
|
|
1275
|
+
// sent, and seek the frame counter over frames already predicted.
|
|
1276
|
+
return;
|
|
1277
|
+
}
|
|
1278
|
+
|
|
800
1279
|
const token = new UUID();
|
|
801
1280
|
token.data = session_token;
|
|
802
1281
|
this.session_token = token;
|
|
@@ -816,7 +1295,22 @@ export class NetworkSession {
|
|
|
816
1295
|
*/
|
|
817
1296
|
this.seek_to_frame(frame_number + 1 + this.#time_dilation.target_buffer_depth);
|
|
818
1297
|
|
|
1298
|
+
// The world is about to be the host's. What this client predicted, sampled or was
|
|
1299
|
+
// told about the one it had is about a world, and a frame numbering, that is gone.
|
|
1300
|
+
this.#prediction_history.clear();
|
|
1301
|
+
this.#pending_auth.clear();
|
|
1302
|
+
this.#reconciled_frame.clear();
|
|
1303
|
+
this.#sampled_actions_per_frame.clear();
|
|
1304
|
+
|
|
819
1305
|
this.#apply_initial_sync(buf, payload_end);
|
|
1306
|
+
this.#binding_answer = BindingAnswer.Synced;
|
|
1307
|
+
|
|
1308
|
+
// Input from here on is predicted on the host's world. What was predicted before —
|
|
1309
|
+
// held since this binding was made, or still in the log from before it — was
|
|
1310
|
+
// predicted on the world just replaced, and is never sent.
|
|
1311
|
+
this.#world_start_frame = this.#local_frame;
|
|
1312
|
+
this.#peer.release_outbound(peer_id, this.#world_start_frame);
|
|
1313
|
+
|
|
820
1314
|
// Reconnecting counts as well as Resyncing: a host that has
|
|
821
1315
|
// finished with our old session readmits us as a fresh peer,
|
|
822
1316
|
// so the snapshot arrives with no RESUME_ACCEPT ahead of it.
|
|
@@ -833,7 +1327,15 @@ export class NetworkSession {
|
|
|
833
1327
|
}
|
|
834
1328
|
});
|
|
835
1329
|
// Host's response to our RESUME_HELLO during reconnect.
|
|
836
|
-
this.#peer.onResumeAccept.add(() => {
|
|
1330
|
+
this.#peer.onResumeAccept.add((peer_id) => {
|
|
1331
|
+
if (this.#binding_answer !== BindingAnswer.Pending) {
|
|
1332
|
+
// stale, as a reject would be: this binding has had its answer
|
|
1333
|
+
return;
|
|
1334
|
+
}
|
|
1335
|
+
this.#binding_answer = BindingAnswer.Resumed;
|
|
1336
|
+
// The host kept the world this client holds, so what the client predicted on it —
|
|
1337
|
+
// while cut off, and since — is owed to the host like any input, late as it is.
|
|
1338
|
+
this.#peer.release_outbound(peer_id, this.#world_start_frame);
|
|
837
1339
|
if (this.#reconnect_state === ReconnectState.Reconnecting
|
|
838
1340
|
|| this.#reconnect_state === ReconnectState.Resyncing) {
|
|
839
1341
|
this.#enter_connected();
|
|
@@ -841,6 +1343,15 @@ export class NetworkSession {
|
|
|
841
1343
|
}
|
|
842
1344
|
});
|
|
843
1345
|
this.#peer.onResumeReject.add((_peer_id, reason_code) => {
|
|
1346
|
+
if (this.#binding_answer !== BindingAnswer.Pending) {
|
|
1347
|
+
// Stale: this binding has had its answer. A host that has finished with our
|
|
1348
|
+
// old session readmits the binding as a fresh peer before it reads our
|
|
1349
|
+
// RESUME_HELLO, and the sync it sends then is the resync this reject asks for,
|
|
1350
|
+
// already applied. Acted on, the reject would throw away the token that sync
|
|
1351
|
+
// issued and wait on a sync already here. A reject that ends the connection is
|
|
1352
|
+
// followed by a DISCONNECT, which still does.
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
844
1355
|
if (this.#reconnect_policy.accept_state_resync) {
|
|
845
1356
|
// Tier-3: drop unconfirmed predictions and wait for
|
|
846
1357
|
// the host to deliver a fresh INITIAL_SYNC.
|
|
@@ -899,15 +1410,36 @@ export class NetworkSession {
|
|
|
899
1410
|
* a peer id is the matchmaking layer's decision, not a race between
|
|
900
1411
|
* whatever connections happen to arrive.
|
|
901
1412
|
*
|
|
1413
|
+
* A client sends its input on the new connection only once the host has
|
|
1414
|
+
* answered it. A RESUME_ACCEPT sends everything predicted meanwhile; an
|
|
1415
|
+
* INITIAL_SYNC drops everything predicted before it, on the world it
|
|
1416
|
+
* replaces. See the network README, "Connecting, and coming back".
|
|
1417
|
+
*
|
|
902
1418
|
* @param {number} remote_peer_id
|
|
903
1419
|
* @param {object} transport
|
|
904
1420
|
*/
|
|
905
1421
|
connect(remote_peer_id, transport) {
|
|
906
1422
|
if (!this.#started) throw new Error("NetworkSession.connect: call start() first");
|
|
907
1423
|
|
|
1424
|
+
// What the peer's previous transport delivered — and its end, if it has ended — is taken
|
|
1425
|
+
// before the new transport is bound, in the order it arrived: a connection that dropped
|
|
1426
|
+
// moments ago has not been noticed until its news is read, and a peer id is only free
|
|
1427
|
+
// once it has been. That holds when this is called from inside that transport's own
|
|
1428
|
+
// delivery — by an application handing on the id of a peer whose DISCONNECT is being
|
|
1429
|
+
// read, say: the flush goes on from the packet after the one being read.
|
|
1430
|
+
const previous = this.#inbound.get(remote_peer_id);
|
|
1431
|
+
if (previous !== undefined) {
|
|
1432
|
+
previous.flush();
|
|
1433
|
+
}
|
|
1434
|
+
|
|
908
1435
|
if (this.role === NetworkSessionRole.Host) {
|
|
909
1436
|
const in_grace = this.#peer_grace_state.has(remote_peer_id);
|
|
910
|
-
this.#
|
|
1437
|
+
const deferred = this.#bind_deferred(remote_peer_id, transport,
|
|
1438
|
+
(t) => this.#server.connect_peer(remote_peer_id, t));
|
|
1439
|
+
// A new connection: nothing it says has been answered yet, and it
|
|
1440
|
+
// has not been given the world.
|
|
1441
|
+
this.#resume_hello_answered.delete(remote_peer_id);
|
|
1442
|
+
this.#initial_sync_given.delete(remote_peer_id);
|
|
911
1443
|
if (in_grace) {
|
|
912
1444
|
// Resume candidate. Wait for RESUME_HELLO; restore
|
|
913
1445
|
// baseline + add to connected_peers on validation.
|
|
@@ -915,10 +1447,10 @@ export class NetworkSession {
|
|
|
915
1447
|
// RESUME_REJECT.
|
|
916
1448
|
} else {
|
|
917
1449
|
// Fresh peer. Queue initial-sync for the next host tick.
|
|
918
|
-
this.#
|
|
1450
|
+
this.#queue_initial_sync(remote_peer_id);
|
|
919
1451
|
this.#connected_peers.add(remote_peer_id);
|
|
920
1452
|
}
|
|
921
|
-
this.#wire_peer_transport_disconnect(remote_peer_id,
|
|
1453
|
+
this.#wire_peer_transport_disconnect(remote_peer_id, deferred);
|
|
922
1454
|
} else {
|
|
923
1455
|
// Client. Release whatever binding this peer id already has: the
|
|
924
1456
|
// reconnect ladder fires on a back-off timer, not on the previous
|
|
@@ -934,11 +1466,19 @@ export class NetworkSession {
|
|
|
934
1466
|
this.#peer.disconnect_peer(remote_peer_id);
|
|
935
1467
|
this.#connected_peers.delete(remote_peer_id);
|
|
936
1468
|
this.#peer_inbound_mark.delete(remote_peer_id);
|
|
937
|
-
this.#
|
|
1469
|
+
const deferred = this.#bind_deferred(remote_peer_id, transport,
|
|
1470
|
+
(t) => this.#client.connect_to_server(remote_peer_id, t));
|
|
938
1471
|
this.#remote_peer_id = remote_peer_id;
|
|
939
|
-
this.#
|
|
940
|
-
this.#
|
|
1472
|
+
this.#wire_client_transport_disconnect(deferred);
|
|
1473
|
+
this.#current_transport = deferred;
|
|
941
1474
|
this.#connected_peers.add(remote_peer_id);
|
|
1475
|
+
// A new binding, and until the host answers it the client does not know which world it
|
|
1476
|
+
// is in: the one it has been predicting on, if the host resumes it (RESUME_ACCEPT), or
|
|
1477
|
+
// the host's, if it sends a snapshot (INITIAL_SYNC) — and input predicted on a world the
|
|
1478
|
+
// snapshot replaces must never reach the host. So what the client predicts meanwhile is
|
|
1479
|
+
// held: sent on an accept, dropped on a sync.
|
|
1480
|
+
this.#binding_answer = BindingAnswer.Pending;
|
|
1481
|
+
this.#peer.hold_outbound(remote_peer_id);
|
|
942
1482
|
|
|
943
1483
|
// Announce ourselves whenever this connect could be a claim on an
|
|
944
1484
|
// id the host still holds a record for: we have a token to prove
|
|
@@ -1057,116 +1597,322 @@ export class NetworkSession {
|
|
|
1057
1597
|
}
|
|
1058
1598
|
|
|
1059
1599
|
/**
|
|
1060
|
-
* Tear down. Idempotent — safe to call from cleanup paths.
|
|
1600
|
+
* Tear down. Idempotent — safe to call from cleanup paths.
|
|
1601
|
+
*/
|
|
1602
|
+
stop() {
|
|
1603
|
+
if (!this.#started) return;
|
|
1604
|
+
|
|
1605
|
+
this.entity_manager.fixedStepTimeScale = 1;
|
|
1606
|
+
|
|
1607
|
+
if (this.#step_open) {
|
|
1608
|
+
// stopped from inside a fixed step: close the frame the step opened
|
|
1609
|
+
this.#step_open = false;
|
|
1610
|
+
if (this.#server !== null) this.#server.end_tick(); else this.#client.end_tick();
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
if (this.#interpolation !== null) {
|
|
1614
|
+
this.#interpolation.restore();
|
|
1615
|
+
this.#interpolation.unregisterSource(this.#interp_source_id);
|
|
1616
|
+
}
|
|
1617
|
+
for (const [entity_id, interpolated] of this.#attached_interpolated) {
|
|
1618
|
+
if (this.world.getComponent(entity_id, Interpolated) === interpolated) {
|
|
1619
|
+
this.world.removeComponentFromEntity(entity_id, Interpolated);
|
|
1620
|
+
}
|
|
1621
|
+
}
|
|
1622
|
+
this.#attached_interpolated.clear();
|
|
1623
|
+
this.#interpolation_pending.clear();
|
|
1624
|
+
this.#pending_auth.clear();
|
|
1625
|
+
this.#reconciled_frame.clear();
|
|
1626
|
+
this.#prediction_history.clear();
|
|
1627
|
+
|
|
1628
|
+
if (this.#identity_observer !== null) {
|
|
1629
|
+
this.#identity_observer.disconnect();
|
|
1630
|
+
this.#identity_observer = null;
|
|
1631
|
+
}
|
|
1632
|
+
for (const [entity_id, listener] of this.#event_listeners) {
|
|
1633
|
+
this.world.removeEntityEventListener(entity_id, "net_mutate_component", listener);
|
|
1634
|
+
}
|
|
1635
|
+
this.#event_listeners.clear();
|
|
1636
|
+
this.#remote_entities.clear();
|
|
1637
|
+
this.#sampled_actions_per_frame.clear();
|
|
1638
|
+
this.#peer_inbound_mark.clear();
|
|
1639
|
+
for (const transport of this.#inbound.values()) {
|
|
1640
|
+
transport.release();
|
|
1641
|
+
}
|
|
1642
|
+
this.#inbound.clear();
|
|
1643
|
+
this.#started = false;
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
// ----------------------------------------------------------------
|
|
1647
|
+
// Per-tick driver
|
|
1648
|
+
// ----------------------------------------------------------------
|
|
1649
|
+
|
|
1650
|
+
/**
|
|
1651
|
+
* **Deprecated; does nothing.** The session used to run its own fixed-step clock here, next to
|
|
1652
|
+
* the engine's: two clocks, so network frame N and the engine's step N were unrelated, and
|
|
1653
|
+
* nothing interpolated against one could be blended on the other. The session now runs on the
|
|
1654
|
+
* `EntityManager`'s fixed step — `entity_manager.update(dt)`, which the engine loop already
|
|
1655
|
+
* calls, drives it — and calling this as well would advance it twice.
|
|
1656
|
+
*
|
|
1657
|
+
* Warns once. Remove the call.
|
|
1658
|
+
*
|
|
1659
|
+
* @deprecated
|
|
1660
|
+
* @param {number} [dt_seconds]
|
|
1661
|
+
*/
|
|
1662
|
+
tick(dt_seconds) {
|
|
1663
|
+
if (!tick_deprecation_warned) {
|
|
1664
|
+
tick_deprecation_warned = true;
|
|
1665
|
+
console.warn('NetworkSession.tick() is deprecated and does nothing: the session runs on the EntityManager fixed step, driven by entity_manager.update(dt). Remove the call.');
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
|
|
1669
|
+
/**
|
|
1670
|
+
* The fixed step about to run opens a network frame. Before it does: the live components are
|
|
1671
|
+
* given back the simulation's truth (a render blend is not state), and everything that arrived
|
|
1672
|
+
* from the network since the last step is applied to it — here, where simulation writes happen,
|
|
1673
|
+
* and not whenever the browser delivers a packet, which is usually between a frame's blend and
|
|
1674
|
+
* its draw.
|
|
1675
|
+
*/
|
|
1676
|
+
#open_step() {
|
|
1677
|
+
if (!this.#started) return;
|
|
1678
|
+
|
|
1679
|
+
this.#interpolation.settle();
|
|
1680
|
+
|
|
1681
|
+
this.#flush_inbound();
|
|
1682
|
+
|
|
1683
|
+
this.#apply_pending_interpolation();
|
|
1684
|
+
|
|
1685
|
+
if (this.#client !== null && this.#pending_auth.size > 0) {
|
|
1686
|
+
this.#apply_pending_corrections();
|
|
1687
|
+
}
|
|
1688
|
+
|
|
1689
|
+
try {
|
|
1690
|
+
if (this.#server !== null) {
|
|
1691
|
+
this.#server.begin_tick(this.#local_frame);
|
|
1692
|
+
} else {
|
|
1693
|
+
this.#client.begin_tick(this.#local_frame);
|
|
1694
|
+
}
|
|
1695
|
+
} catch (e) {
|
|
1696
|
+
// the frame is spent: the next step moves on to the next one rather than repeat it
|
|
1697
|
+
// over what this one already applied
|
|
1698
|
+
this.#local_frame++;
|
|
1699
|
+
throw e;
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
this.#step_open = true;
|
|
1703
|
+
}
|
|
1704
|
+
|
|
1705
|
+
/**
|
|
1706
|
+
* The fixed step has run: close its network frame.
|
|
1707
|
+
*/
|
|
1708
|
+
#close_step() {
|
|
1709
|
+
if (!this.#step_open) return;
|
|
1710
|
+
|
|
1711
|
+
try {
|
|
1712
|
+
if (this.#server !== null) {
|
|
1713
|
+
// runs the frame's local sim, then publishes (onBeforeTickClose), then closes it
|
|
1714
|
+
this.#server.end_tick();
|
|
1715
|
+
} else {
|
|
1716
|
+
this.#client.end_tick();
|
|
1717
|
+
this.#send_frame_marker(this.#local_frame);
|
|
1718
|
+
if (this.#reconcile === NetworkSessionReconcile.Correct) {
|
|
1719
|
+
this.#record_prediction(this.#local_frame);
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
} finally {
|
|
1723
|
+
this.#step_open = false;
|
|
1724
|
+
this.#local_frame++;
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
|
|
1728
|
+
/**
|
|
1729
|
+
* Deliver what every peer's transport has held since the last step, and let go of the
|
|
1730
|
+
* transports of peers no longer connected.
|
|
1731
|
+
*/
|
|
1732
|
+
#flush_inbound() {
|
|
1733
|
+
for (const [peer_id, transport] of this.#inbound) {
|
|
1734
|
+
if (!this.#peer.is_connected(peer_id)) {
|
|
1735
|
+
transport.release();
|
|
1736
|
+
this.#inbound.delete(peer_id);
|
|
1737
|
+
continue;
|
|
1738
|
+
}
|
|
1739
|
+
transport.flush();
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
|
|
1743
|
+
/**
|
|
1744
|
+
* Bind `peer_id` to `transport` through `bind`, with the transport's traffic held for
|
|
1745
|
+
* {@link #open_step}. Whatever held the peer's traffic before is let go once the new binding
|
|
1746
|
+
* stands; if binding throws, nothing changes.
|
|
1747
|
+
*
|
|
1748
|
+
* @param {number} peer_id
|
|
1749
|
+
* @param {object} transport
|
|
1750
|
+
* @param {(deferred: DeferredTransport) => void} bind
|
|
1751
|
+
* @returns {DeferredTransport}
|
|
1752
|
+
*/
|
|
1753
|
+
#bind_deferred(peer_id, transport, bind) {
|
|
1754
|
+
const deferred = new DeferredTransport(transport);
|
|
1755
|
+
|
|
1756
|
+
try {
|
|
1757
|
+
bind(deferred);
|
|
1758
|
+
} catch (e) {
|
|
1759
|
+
deferred.release();
|
|
1760
|
+
throw e;
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
const previous = this.#inbound.get(peer_id);
|
|
1764
|
+
if (previous !== undefined) {
|
|
1765
|
+
previous.release();
|
|
1766
|
+
}
|
|
1767
|
+
this.#inbound.set(peer_id, deferred);
|
|
1768
|
+
|
|
1769
|
+
return deferred;
|
|
1770
|
+
}
|
|
1771
|
+
|
|
1772
|
+
/**
|
|
1773
|
+
* Host, end of step: record every replicated component whose wire image differs from what the
|
|
1774
|
+
* peers hold, into the still-open frame, for the action stream to carry. Recorded, not
|
|
1775
|
+
* executed — see {@link SimActionExecutor#record}. A component an action wrote this step and
|
|
1776
|
+
* nothing changed since is not sent again: the peers apply the action.
|
|
1777
|
+
*/
|
|
1778
|
+
#publish_simulated_changes() {
|
|
1779
|
+
const world = this.world;
|
|
1780
|
+
const executor = this.#peer.executor;
|
|
1781
|
+
const scratch = this.#scratch_publish_buf;
|
|
1782
|
+
const changed_entities = executor.changed_entities;
|
|
1783
|
+
|
|
1784
|
+
for (const entity_id of this.#event_listeners.keys()) {
|
|
1785
|
+
const identity = world.getComponent(entity_id, NetworkIdentity);
|
|
1786
|
+
if (identity === undefined || identity.network_id < 0) continue;
|
|
1787
|
+
|
|
1788
|
+
for (const [ComponentClass, desc] of this.#replicated) {
|
|
1789
|
+
if (ComponentClass === NetworkIdentity) continue;
|
|
1790
|
+
|
|
1791
|
+
const live = world.getComponent(entity_id, ComponentClass);
|
|
1792
|
+
if (live === undefined) continue;
|
|
1793
|
+
|
|
1794
|
+
const type_id = desc.interp_type_id;
|
|
1795
|
+
|
|
1796
|
+
scratch.position = 0;
|
|
1797
|
+
this.binary_registry.getAdapter(ComponentClass.typeName).serialize(scratch, live);
|
|
1798
|
+
const length = scratch.position;
|
|
1799
|
+
|
|
1800
|
+
if (!this.#remember_published(entity_id, type_id, scratch.raw_bytes, length)) continue;
|
|
1801
|
+
|
|
1802
|
+
const action = this.#peer.action_registry.acquire(this.#ReplaceComponentAction);
|
|
1803
|
+
try {
|
|
1804
|
+
action.network_id = identity.network_id;
|
|
1805
|
+
action.component_type_id = type_id;
|
|
1806
|
+
action.payload_buf.position = 0;
|
|
1807
|
+
action.payload_buf.writeBytes(scratch.raw_bytes, 0, length);
|
|
1808
|
+
action.payload_length = length;
|
|
1809
|
+
executor.record(action);
|
|
1810
|
+
} finally {
|
|
1811
|
+
this.#peer.action_registry.release(action);
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1814
|
+
if (changed_entities !== null) changed_entities.add(identity.network_id);
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
|
|
1819
|
+
/**
|
|
1820
|
+
* Host: an action wrote `ComponentClass` of `entity_id`; the peers will hold what it wrote.
|
|
1821
|
+
* @param {number} entity_id
|
|
1822
|
+
* @param {Function} ComponentClass
|
|
1823
|
+
*/
|
|
1824
|
+
#note_published(entity_id, ComponentClass) {
|
|
1825
|
+
const desc = this.#replicated.get(ComponentClass);
|
|
1826
|
+
if (desc === undefined || ComponentClass === NetworkIdentity) return;
|
|
1827
|
+
|
|
1828
|
+
const live = this.world.getComponent(entity_id, ComponentClass);
|
|
1829
|
+
if (live === undefined) return;
|
|
1830
|
+
|
|
1831
|
+
const scratch = this.#scratch_publish_buf;
|
|
1832
|
+
scratch.position = 0;
|
|
1833
|
+
this.binary_registry.getAdapter(ComponentClass.typeName).serialize(scratch, live);
|
|
1834
|
+
this.#remember_published(entity_id, desc.interp_type_id, scratch.raw_bytes, scratch.position);
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1837
|
+
/**
|
|
1838
|
+
* Set what the peers hold for `(entity_id, type_id)`.
|
|
1839
|
+
* @param {number} entity_id
|
|
1840
|
+
* @param {number} type_id
|
|
1841
|
+
* @param {Uint8Array} bytes
|
|
1842
|
+
* @param {number} length
|
|
1843
|
+
* @returns {boolean} whether it differs from what was held before
|
|
1061
1844
|
*/
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
if (
|
|
1065
|
-
|
|
1066
|
-
this.#
|
|
1845
|
+
#remember_published(entity_id, type_id, bytes, length) {
|
|
1846
|
+
let published = this.#published.get(entity_id);
|
|
1847
|
+
if (published === undefined) {
|
|
1848
|
+
published = [];
|
|
1849
|
+
this.#published.set(entity_id, published);
|
|
1067
1850
|
}
|
|
1068
|
-
|
|
1069
|
-
|
|
1851
|
+
while (published.length <= type_id) published.push(null);
|
|
1852
|
+
|
|
1853
|
+
let held = published[type_id];
|
|
1854
|
+
if (held !== null && held.length === length && bytes_equal(bytes, held.bytes, length)) {
|
|
1855
|
+
return false;
|
|
1070
1856
|
}
|
|
1071
|
-
this.#event_listeners.clear();
|
|
1072
|
-
this.#remote_entities.clear();
|
|
1073
|
-
this.#sampled_actions_per_frame.clear();
|
|
1074
|
-
this.#peer_inbound_mark.clear();
|
|
1075
|
-
this.#started = false;
|
|
1076
|
-
}
|
|
1077
1857
|
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1858
|
+
if (held === null || held.bytes.length < length) {
|
|
1859
|
+
held = { bytes: new Uint8Array(Math.max(length, 32)), length: 0 };
|
|
1860
|
+
published[type_id] = held;
|
|
1861
|
+
}
|
|
1862
|
+
held.bytes.set(bytes.subarray(0, length), 0);
|
|
1863
|
+
held.length = length;
|
|
1864
|
+
|
|
1865
|
+
return true;
|
|
1866
|
+
}
|
|
1081
1867
|
|
|
1082
1868
|
/**
|
|
1083
|
-
*
|
|
1084
|
-
*
|
|
1085
|
-
* advances at `1 / dilation_factor` per fixed step.
|
|
1086
|
-
*
|
|
1087
|
-
* @param {number} dt_seconds elapsed wall seconds since the previous call
|
|
1869
|
+
* Once per rendered frame: the work paced by wall time rather than by the simulation.
|
|
1870
|
+
* @param {number} dt_seconds
|
|
1088
1871
|
*/
|
|
1089
|
-
|
|
1872
|
+
#on_frame(dt_seconds) {
|
|
1090
1873
|
if (!this.#started) return;
|
|
1091
1874
|
|
|
1092
|
-
// Restore canonical form before sim work. The executor's
|
|
1093
|
-
// `before_execute` hook also covers per-action paths (e.g.
|
|
1094
|
-
// packets delivered between session.tick calls).
|
|
1095
|
-
this.normalize_if_dirty();
|
|
1096
|
-
|
|
1097
1875
|
const dt_ms = dt_seconds * 1000;
|
|
1098
1876
|
|
|
1099
|
-
|
|
1877
|
+
this.#clock_ms += dt_ms;
|
|
1878
|
+
|
|
1879
|
+
// the playhead moves with the clock whether or not anything is drawn from it this frame
|
|
1880
|
+
this.#playout.window(this.#clock_ms);
|
|
1881
|
+
|
|
1100
1882
|
if (this.role === NetworkSessionRole.Host) {
|
|
1101
|
-
|
|
1883
|
+
// Host: expire grace-window peers whose deadline has passed.
|
|
1884
|
+
this.#expire_grace_peers(this.#clock_ms);
|
|
1102
1885
|
} else {
|
|
1103
1886
|
// Client: drive the reconnect timer.
|
|
1104
1887
|
this.#tick_reconnect(dt_ms);
|
|
1888
|
+
|
|
1889
|
+
// Time dilation: run the whole local simulation a few percent fast or slow, as the
|
|
1890
|
+
// host asks, by stretching the wall time each step consumes. The step itself — and so
|
|
1891
|
+
// every system's dt — is unchanged, and the render alpha stays a true fraction of it.
|
|
1892
|
+
this.entity_manager.fixedStepTimeScale = 1 / this.#client.dilation_factor;
|
|
1105
1893
|
}
|
|
1106
1894
|
|
|
1107
1895
|
// Idle reaping: a connected peer that has gone silent past the timeout
|
|
1108
|
-
// is reaped (host → grace, client → reconnect ladder).
|
|
1109
|
-
// deterministic tick-dt accumulator (not wall-clock), so it's testable.
|
|
1896
|
+
// is reaped (host → grace, client → reconnect ladder).
|
|
1110
1897
|
if (this.#connection_timeout_ms > 0) {
|
|
1111
|
-
this.#liveness_clock_ms += dt_ms;
|
|
1112
1898
|
this.#reap_silent_peers();
|
|
1113
1899
|
}
|
|
1114
|
-
|
|
1115
|
-
this.#sim_accum_ms += dt_ms;
|
|
1116
|
-
let steps = 0;
|
|
1117
|
-
while (this.#sim_accum_ms >= this.tick_period_ms && steps < MAX_FIXED_STEPS_PER_TICK) {
|
|
1118
|
-
this.#sim_accum_ms -= this.tick_period_ms;
|
|
1119
|
-
this.#simulate_one_step();
|
|
1120
|
-
steps++;
|
|
1121
|
-
}
|
|
1122
|
-
if (steps === MAX_FIXED_STEPS_PER_TICK) this.#sim_accum_ms = 0;
|
|
1123
|
-
|
|
1124
|
-
// Per-render-frame: smooth interpolated rendering of remote
|
|
1125
|
-
// entities. Marks the live ECD as polluted so the next sim-tick
|
|
1126
|
-
// or reconcile starts with a normalize.
|
|
1127
|
-
this.#render_interpolated_entities();
|
|
1128
1900
|
}
|
|
1129
1901
|
|
|
1130
1902
|
/**
|
|
1131
|
-
*
|
|
1132
|
-
*
|
|
1133
|
-
*
|
|
1903
|
+
* Put the truth back wherever a render blend is in the live components — the
|
|
1904
|
+
* {@link InterpolationSystem}'s restore. Anything written over a blend since goes with it; what
|
|
1905
|
+
* is written after this call stays. Idempotent and cheap when nothing is blended.
|
|
1134
1906
|
*
|
|
1135
|
-
*
|
|
1136
|
-
*
|
|
1137
|
-
*
|
|
1138
|
-
*
|
|
1139
|
-
* @private
|
|
1907
|
+
* Runs before every action the executor applies (an action captures the prior value of what it
|
|
1908
|
+
* overwrites, and that must not be a blend), before a reconciliation, and at the start of every
|
|
1909
|
+
* fixed step. Game code that writes a networked entity's state between steps calls it first.
|
|
1910
|
+
* The name is kept from when the session owned its own blend.
|
|
1140
1911
|
*/
|
|
1141
1912
|
normalize_if_dirty() {
|
|
1142
|
-
if (!this.render_dirty) return;
|
|
1143
1913
|
this.render_dirty = false;
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
if (this.#remote_entities.size === 0) return;
|
|
1147
|
-
|
|
1148
|
-
const scratch = this.#scratch_interp_buf;
|
|
1149
|
-
const tick = this.#playout.latest_frame;
|
|
1150
|
-
|
|
1151
|
-
for (const entity_id of this.#remote_entities) {
|
|
1152
|
-
const identity = this.world.getComponent(entity_id, NetworkIdentity);
|
|
1153
|
-
if (identity === undefined || identity.network_id < 0) continue;
|
|
1154
|
-
for (const [ComponentClass, desc] of this.#replicated) {
|
|
1155
|
-
if (desc.interp === null) continue;
|
|
1156
|
-
const live = this.world.getComponent(entity_id, ComponentClass);
|
|
1157
|
-
if (live === undefined) continue;
|
|
1158
|
-
scratch.position = 0;
|
|
1159
|
-
// tick_a === tick_b, t = 0 — degenerate "snap to single
|
|
1160
|
-
// snapshot" lerp. Output equals the stored snapshot.
|
|
1161
|
-
const ok = this.#interp_log.interpolate(
|
|
1162
|
-
scratch, identity.network_id, desc.interp_type_id,
|
|
1163
|
-
tick, tick, 0, desc.interp,
|
|
1164
|
-
);
|
|
1165
|
-
if (!ok) continue;
|
|
1166
|
-
scratch.position = 0;
|
|
1167
|
-
const adapter = this.binary_registry.getAdapter(ComponentClass.typeName);
|
|
1168
|
-
adapter.deserialize(scratch, live);
|
|
1169
|
-
}
|
|
1914
|
+
if (this.#interpolation !== null) {
|
|
1915
|
+
this.#interpolation.restore();
|
|
1170
1916
|
}
|
|
1171
1917
|
}
|
|
1172
1918
|
|
|
@@ -1324,13 +2070,23 @@ export class NetworkSession {
|
|
|
1324
2070
|
* A client now seeks automatically on INITIAL_SYNC. This is the manual door, for a caller that
|
|
1325
2071
|
* computes its own lead.
|
|
1326
2072
|
*
|
|
2073
|
+
* A client sends the host nothing it predicted before its last sync, and knows it by frame: its
|
|
2074
|
+
* input starts at the frame the sync sought to. A caller whose own lead is shorter moves that
|
|
2075
|
+
* start back with it, so what it predicts on the synced world is sent however it counts it.
|
|
2076
|
+
*
|
|
1327
2077
|
* @param {number} frame
|
|
1328
2078
|
*/
|
|
1329
2079
|
seek_to_frame(frame) {
|
|
1330
2080
|
assert.isNonNegativeInteger(frame, 'frame');
|
|
1331
2081
|
|
|
1332
2082
|
this.#local_frame = frame;
|
|
1333
|
-
|
|
2083
|
+
|
|
2084
|
+
if (frame < this.#world_start_frame) {
|
|
2085
|
+
this.#world_start_frame = frame;
|
|
2086
|
+
if (this.#binding_answer !== BindingAnswer.Pending && this.#peer.is_connected(this.#remote_peer_id)) {
|
|
2087
|
+
this.#peer.release_outbound(this.#remote_peer_id, frame);
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
1334
2090
|
}
|
|
1335
2091
|
|
|
1336
2092
|
// ----------------------------------------------------------------
|
|
@@ -1353,6 +2109,7 @@ export class NetworkSession {
|
|
|
1353
2109
|
if (identity.owner_peer_id !== this.local_peer_id) {
|
|
1354
2110
|
this.#remote_entities.add(entity_id);
|
|
1355
2111
|
}
|
|
2112
|
+
this.#interpolation_pending.add(entity_id);
|
|
1356
2113
|
// Per-entity event listener for net_mutate_component.
|
|
1357
2114
|
const listener = (payload) => this.#on_net_mutate_component(entity_id, payload);
|
|
1358
2115
|
this.world.addEntityEventListener(entity_id, "net_mutate_component", listener);
|
|
@@ -1366,6 +2123,10 @@ export class NetworkSession {
|
|
|
1366
2123
|
this.#event_listeners.delete(entity_id);
|
|
1367
2124
|
}
|
|
1368
2125
|
this.#remote_entities.delete(entity_id);
|
|
2126
|
+
this.#published.delete(entity_id);
|
|
2127
|
+
this.#prediction_history.forget(entity_id);
|
|
2128
|
+
// take back our Interpolated at the next step or frame, if the entity outlives its identity
|
|
2129
|
+
this.#interpolation_pending.add(entity_id);
|
|
1369
2130
|
}
|
|
1370
2131
|
|
|
1371
2132
|
/**
|
|
@@ -1387,7 +2148,7 @@ export class NetworkSession {
|
|
|
1387
2148
|
}
|
|
1388
2149
|
const desc = this.#replicated.get(component_type);
|
|
1389
2150
|
if (desc === undefined) {
|
|
1390
|
-
throw new Error(`net_mutate_component: ${component_type.typeName ?? component_type.name} is not replicated;
|
|
2151
|
+
throw new Error(`net_mutate_component: ${component_type.typeName ?? component_type.name} is not replicated; replicate it (replicate_interpolated or replicate_discrete) before mutating`);
|
|
1391
2152
|
}
|
|
1392
2153
|
|
|
1393
2154
|
const network_id = this.#peer.slot_table.network_for(entity_id);
|
|
@@ -1497,32 +2258,16 @@ export class NetworkSession {
|
|
|
1497
2258
|
// Internal: per-step simulation
|
|
1498
2259
|
// ----------------------------------------------------------------
|
|
1499
2260
|
|
|
1500
|
-
#simulate_one_step() {
|
|
1501
|
-
if (this.role === NetworkSessionRole.Host) {
|
|
1502
|
-
this.#server.tick(this.#local_frame);
|
|
1503
|
-
this.#local_frame++;
|
|
1504
|
-
return;
|
|
1505
|
-
}
|
|
1506
|
-
// Client. Dilated tick rate: each fixed step advances by
|
|
1507
|
-
// `1 / dilation_factor` (capped at MAX_CLIENT_DILATED_TICKS_PER_STEP).
|
|
1508
|
-
this.#local_frame_accum += 1.0 / this.#client.dilation_factor;
|
|
1509
|
-
let inner = 0;
|
|
1510
|
-
while (this.#local_frame_accum >= 1.0 && inner < MAX_CLIENT_DILATED_TICKS_PER_STEP) {
|
|
1511
|
-
this.#local_frame_accum -= 1.0;
|
|
1512
|
-
this.#client.tick(this.#local_frame);
|
|
1513
|
-
this.#send_empty_ack_packet();
|
|
1514
|
-
this.#local_frame++;
|
|
1515
|
-
inner++;
|
|
1516
|
-
}
|
|
1517
|
-
}
|
|
1518
|
-
|
|
1519
2261
|
/**
|
|
1520
|
-
*
|
|
1521
|
-
* baseline
|
|
2262
|
+
* The tick's keep-alive to the host: a frame marker, which advances the channel's seq/ack
|
|
2263
|
+
* baseline like any packet and tells the host how far this client's clock has run — the depth
|
|
2264
|
+
* its time dilation steers by — on ticks that carry no input as well as on ones that do.
|
|
2265
|
+
*
|
|
2266
|
+
* @param {number} frame the frame just simulated
|
|
1522
2267
|
*/
|
|
1523
|
-
#
|
|
2268
|
+
#send_frame_marker(frame) {
|
|
1524
2269
|
for (const peer_id of this.#connected_peers) {
|
|
1525
|
-
this.#peer.
|
|
2270
|
+
this.#peer.send_frame_marker(peer_id, frame);
|
|
1526
2271
|
}
|
|
1527
2272
|
}
|
|
1528
2273
|
|
|
@@ -1577,6 +2322,21 @@ export class NetworkSession {
|
|
|
1577
2322
|
}
|
|
1578
2323
|
|
|
1579
2324
|
|
|
2325
|
+
/**
|
|
2326
|
+
* Queue `peer_id`'s INITIAL_SYNC, unless its connection has been given
|
|
2327
|
+
* one already — queued, or queued and sent. These are the host's only
|
|
2328
|
+
* full-world sends, so how many a connection gets is the host's decision:
|
|
2329
|
+
* one, when it takes the connection for a fresh peer — as `connect()`
|
|
2330
|
+
* binds it, or after refusing its claim to resume. Nothing the peer sends
|
|
2331
|
+
* afterwards earns it another.
|
|
2332
|
+
* @param {number} peer_id
|
|
2333
|
+
*/
|
|
2334
|
+
#queue_initial_sync(peer_id) {
|
|
2335
|
+
if (this.#initial_sync_given.has(peer_id)) return;
|
|
2336
|
+
this.#initial_sync_given.add(peer_id);
|
|
2337
|
+
this.#pending_initial_sync.set(peer_id, 2);
|
|
2338
|
+
}
|
|
2339
|
+
|
|
1580
2340
|
/**
|
|
1581
2341
|
* Emit a Snapshotter-format payload to a freshly-connected peer.
|
|
1582
2342
|
* Generates and stashes a UUID v1 session token on first send,
|
|
@@ -1619,6 +2379,9 @@ export class NetworkSession {
|
|
|
1619
2379
|
*
|
|
1620
2380
|
*/
|
|
1621
2381
|
#apply_initial_sync(buffer, payload_end) {
|
|
2382
|
+
// written over the truth, not over a render blend that a restore would then put back
|
|
2383
|
+
this.normalize_if_dirty();
|
|
2384
|
+
|
|
1622
2385
|
const entity_count = buffer.readUintVar();
|
|
1623
2386
|
for (let i = 0; i < entity_count; i++) {
|
|
1624
2387
|
const network_id = buffer.readUintVar();
|
|
@@ -1644,6 +2407,8 @@ export class NetworkSession {
|
|
|
1644
2407
|
this.world.addComponentToEntity(local_entity_id, component);
|
|
1645
2408
|
} else {
|
|
1646
2409
|
adapter.deserialize(buffer, existing);
|
|
2410
|
+
adapter.announce(this.world, local_entity_id);
|
|
2411
|
+
this.#note_moved(local_entity_id);
|
|
1647
2412
|
|
|
1648
2413
|
/*
|
|
1649
2414
|
Re-decide what this entity is to us.
|
|
@@ -1706,6 +2471,7 @@ export class NetworkSession {
|
|
|
1706
2471
|
} else {
|
|
1707
2472
|
this.#remote_entities.add(entity_id);
|
|
1708
2473
|
}
|
|
2474
|
+
this.#interpolation_pending.add(entity_id);
|
|
1709
2475
|
}
|
|
1710
2476
|
|
|
1711
2477
|
/**
|
|
@@ -1800,7 +2566,7 @@ export class NetworkSession {
|
|
|
1800
2566
|
this.#pending_initial_sync.delete(peer_id);
|
|
1801
2567
|
this.#unwire_peer_transport_disconnect(peer_id);
|
|
1802
2568
|
this.#peer_grace_state.set(peer_id, {
|
|
1803
|
-
deadline_ms:
|
|
2569
|
+
deadline_ms: this.#clock_ms + this.#server_resume_grace_ms,
|
|
1804
2570
|
last_acked,
|
|
1805
2571
|
});
|
|
1806
2572
|
this.onPeerLost.send2(peer_id, reason);
|
|
@@ -1808,11 +2574,24 @@ export class NetworkSession {
|
|
|
1808
2574
|
|
|
1809
2575
|
/**
|
|
1810
2576
|
* Validate a RESUME_HELLO and either welcome the peer back (restore
|
|
1811
|
-
* baseline + send RESUME_ACCEPT) or reject with a reason code.
|
|
1812
|
-
*
|
|
1813
|
-
*
|
|
2577
|
+
* baseline + send RESUME_ACCEPT) or reject with a reason code. A claim
|
|
2578
|
+
* the host cannot honour is readmitted as a fresh peer, whose
|
|
2579
|
+
* INITIAL_SYNC is the Tier-3 resync; one it must not honour is kicked.
|
|
2580
|
+
*
|
|
2581
|
+
* Answered once per connection; see the first branch.
|
|
1814
2582
|
*/
|
|
1815
2583
|
#on_resume_hello(transport_peer_id, claimed_peer_id, last_acked_frame, has_token, claimed_token_bytes) {
|
|
2584
|
+
// A client says RESUME_HELLO at most once per connection, from
|
|
2585
|
+
// `connect()`, so a second one on the same connection is a duplicated
|
|
2586
|
+
// datagram — the channel passes those on — or a peer asking the host to
|
|
2587
|
+
// do its work again. Every answer below costs the host something: a
|
|
2588
|
+
// packet at least, a serialization of its whole world at most. What a
|
|
2589
|
+
// connection gets is settled the first time it asks, and the rest are
|
|
2590
|
+
// ignored: unanswered rather than kicked, since a kick would also land
|
|
2591
|
+
// on a client whose one hello the network happened to deliver twice.
|
|
2592
|
+
if (this.#resume_hello_answered.has(transport_peer_id)) return;
|
|
2593
|
+
this.#resume_hello_answered.add(transport_peer_id);
|
|
2594
|
+
|
|
1816
2595
|
// Engine convention: the matchmaking layer routes the reconnecting
|
|
1817
2596
|
// transport to the same `peer_id` it had before. If `claimed_peer_id`
|
|
1818
2597
|
// disagrees with `transport_peer_id`, the matchmaker mis-routed —
|
|
@@ -1866,12 +2645,17 @@ export class NetworkSession {
|
|
|
1866
2645
|
}
|
|
1867
2646
|
const grace = this.#peer_grace_state.get(claimed_peer_id);
|
|
1868
2647
|
if (grace === undefined) {
|
|
1869
|
-
//
|
|
1870
|
-
//
|
|
1871
|
-
//
|
|
2648
|
+
// No resume record to validate against. There was none when
|
|
2649
|
+
// `connect()` bound this connection either — a record outlives
|
|
2650
|
+
// neither grace expiry nor `drop_peer`, and both release the
|
|
2651
|
+
// channel of an attempt waiting on it — so the connection was
|
|
2652
|
+
// taken for a fresh peer: it is in the live set, and its
|
|
2653
|
+
// INITIAL_SYNC is queued or already sent. Refuse the claim, and
|
|
2654
|
+
// treat the peer as the fresh one it is; the sync it has is the
|
|
2655
|
+
// resync, and `#queue_initial_sync` does not give a connection
|
|
2656
|
+
// the world twice.
|
|
1872
2657
|
this.#peer.send_resume_reject(transport_peer_id, ResumeRejectReason.UnknownPeer);
|
|
1873
|
-
|
|
1874
|
-
this.#pending_initial_sync.set(transport_peer_id, 2);
|
|
2658
|
+
this.#queue_initial_sync(transport_peer_id);
|
|
1875
2659
|
this.#connected_peers.add(transport_peer_id);
|
|
1876
2660
|
return;
|
|
1877
2661
|
}
|
|
@@ -1879,7 +2663,7 @@ export class NetworkSession {
|
|
|
1879
2663
|
if (expected_token === undefined) {
|
|
1880
2664
|
this.#peer.send_resume_reject(transport_peer_id, ResumeRejectReason.UnknownPeer);
|
|
1881
2665
|
this.#peer_grace_state.delete(claimed_peer_id);
|
|
1882
|
-
this.#
|
|
2666
|
+
this.#queue_initial_sync(transport_peer_id);
|
|
1883
2667
|
this.#connected_peers.add(transport_peer_id);
|
|
1884
2668
|
return;
|
|
1885
2669
|
}
|
|
@@ -1919,7 +2703,7 @@ export class NetworkSession {
|
|
|
1919
2703
|
if (last_acked_frame + 1 < ring_floor) {
|
|
1920
2704
|
this.#peer.send_resume_reject(transport_peer_id, ResumeRejectReason.StaleFrame);
|
|
1921
2705
|
this.#peer_grace_state.delete(claimed_peer_id);
|
|
1922
|
-
this.#
|
|
2706
|
+
this.#queue_initial_sync(transport_peer_id);
|
|
1923
2707
|
this.#connected_peers.add(transport_peer_id);
|
|
1924
2708
|
return;
|
|
1925
2709
|
}
|
|
@@ -1996,18 +2780,20 @@ export class NetworkSession {
|
|
|
1996
2780
|
* @private
|
|
1997
2781
|
*/
|
|
1998
2782
|
#peer_is_silent(peer_id) {
|
|
1999
|
-
|
|
2783
|
+
// what the peer has sent, whether or not the next step has applied it yet
|
|
2784
|
+
const inbound = this.#inbound.get(peer_id);
|
|
2785
|
+
const count = inbound !== undefined ? inbound.received_count : this.#peer.inbound_count(peer_id);
|
|
2000
2786
|
const mark = this.#peer_inbound_mark.get(peer_id);
|
|
2001
2787
|
if (mark === undefined) {
|
|
2002
|
-
this.#peer_inbound_mark.set(peer_id, { count, since_ms: this.#
|
|
2788
|
+
this.#peer_inbound_mark.set(peer_id, { count, since_ms: this.#clock_ms });
|
|
2003
2789
|
return false;
|
|
2004
2790
|
}
|
|
2005
2791
|
if (count !== mark.count) {
|
|
2006
2792
|
mark.count = count;
|
|
2007
|
-
mark.since_ms = this.#
|
|
2793
|
+
mark.since_ms = this.#clock_ms;
|
|
2008
2794
|
return false;
|
|
2009
2795
|
}
|
|
2010
|
-
return this.#
|
|
2796
|
+
return this.#clock_ms - mark.since_ms >= this.#connection_timeout_ms;
|
|
2011
2797
|
}
|
|
2012
2798
|
|
|
2013
2799
|
// ----------------------------------------------------------------
|
|
@@ -2041,7 +2827,7 @@ export class NetworkSession {
|
|
|
2041
2827
|
// Stop treating this peer as a live send target. The channel is
|
|
2042
2828
|
// gone, but `#remote_peer_id` is deliberately kept so the reconnect
|
|
2043
2829
|
// ladder can re-`connect()` to the same id. Without this delete,
|
|
2044
|
-
// `#
|
|
2830
|
+
// `#send_frame_marker` (driven every tick) dereferences the
|
|
2045
2831
|
// now-undefined channel and throws — which would crash the very
|
|
2046
2832
|
// tick loop that drives the reconnect ladder.
|
|
2047
2833
|
this.#connected_peers.delete(this.#remote_peer_id);
|
|
@@ -2151,13 +2937,232 @@ export class NetworkSession {
|
|
|
2151
2937
|
// Internal: client predict-reconcile wiring
|
|
2152
2938
|
// ----------------------------------------------------------------
|
|
2153
2939
|
|
|
2940
|
+
/**
|
|
2941
|
+
* A scratch instance of `ComponentClass`, for decoding wire bytes without touching the world.
|
|
2942
|
+
* @param {Function} ComponentClass
|
|
2943
|
+
* @param {number} slot 0: the host's state, 1: the prediction, 2: a later prediction
|
|
2944
|
+
* @returns {object}
|
|
2945
|
+
*/
|
|
2946
|
+
#scratch_of(ComponentClass, slot) {
|
|
2947
|
+
let instances = this.#decode_scratch.get(ComponentClass);
|
|
2948
|
+
if (instances === undefined) {
|
|
2949
|
+
instances = [new ComponentClass(), new ComponentClass(), new ComponentClass()];
|
|
2950
|
+
this.#decode_scratch.set(ComponentClass, instances);
|
|
2951
|
+
}
|
|
2952
|
+
return instances[slot];
|
|
2953
|
+
}
|
|
2954
|
+
|
|
2955
|
+
/**
|
|
2956
|
+
* Decode `length` bytes of `bytes` into `target` with `ComponentClass`'s replication adapter.
|
|
2957
|
+
*/
|
|
2958
|
+
#decode_into(ComponentClass, bytes, length, target) {
|
|
2959
|
+
const buffer = this.#scratch_interp_buf;
|
|
2960
|
+
buffer.position = 0;
|
|
2961
|
+
buffer.writeBytes(bytes, 0, length);
|
|
2962
|
+
buffer.position = 0;
|
|
2963
|
+
this.binary_registry.getAdapter(ComponentClass.typeName).deserialize(buffer, target);
|
|
2964
|
+
}
|
|
2965
|
+
|
|
2966
|
+
/**
|
|
2967
|
+
* AUTH_STATE, {@link NetworkSessionReconcile.Correct}: split the payload into its components'
|
|
2968
|
+
* wire bytes now — the receive buffer is the peer's and is reused — and keep the newest per
|
|
2969
|
+
* entity for the next step. Parsing mirrors the host's writer: every replicated component the
|
|
2970
|
+
* entity carries, in `#replicated` order.
|
|
2971
|
+
*/
|
|
2972
|
+
#queue_auth_state(server_frame, network_id, buffer) {
|
|
2973
|
+
const pending = this.#pending_auth.get(network_id);
|
|
2974
|
+
if (pending !== undefined && pending.frame >= server_frame) return;
|
|
2975
|
+
|
|
2976
|
+
const reconciled = this.#reconciled_frame.get(network_id);
|
|
2977
|
+
if (reconciled !== undefined && reconciled >= server_frame) return;
|
|
2978
|
+
|
|
2979
|
+
const entity_id = this.#peer.slot_table.entity_for(network_id);
|
|
2980
|
+
if (entity_id < 0) return;
|
|
2981
|
+
|
|
2982
|
+
const parts = [];
|
|
2983
|
+
for (const [ComponentClass, desc] of this.#replicated) {
|
|
2984
|
+
if (this.world.getComponent(entity_id, ComponentClass) === undefined) {
|
|
2985
|
+
parts.push(null);
|
|
2986
|
+
continue;
|
|
2987
|
+
}
|
|
2988
|
+
const start = buffer.position;
|
|
2989
|
+
this.binary_registry.getAdapter(ComponentClass.typeName).deserialize(buffer, this.#scratch_of(ComponentClass, 0));
|
|
2990
|
+
parts.push({ type_id: desc.interp_type_id, bytes: buffer.raw_bytes.slice(start, buffer.position) });
|
|
2991
|
+
}
|
|
2992
|
+
|
|
2993
|
+
this.#pending_auth.set(network_id, { frame: server_frame, parts });
|
|
2994
|
+
}
|
|
2995
|
+
|
|
2996
|
+
/**
|
|
2997
|
+
* Client, end of step: remember what was predicted for every entity this client owns.
|
|
2998
|
+
* @param {number} frame
|
|
2999
|
+
*/
|
|
3000
|
+
#record_prediction(frame) {
|
|
3001
|
+
const scratch = this.#scratch_send_buf;
|
|
3002
|
+
const world = this.world;
|
|
3003
|
+
|
|
3004
|
+
for (const entity_id of this.#event_listeners.keys()) {
|
|
3005
|
+
if (this.#remote_entities.has(entity_id)) continue;
|
|
3006
|
+
|
|
3007
|
+
const identity = world.getComponent(entity_id, NetworkIdentity);
|
|
3008
|
+
if (identity === undefined || identity.network_id < 0) continue;
|
|
3009
|
+
|
|
3010
|
+
for (const [ComponentClass, desc] of this.#replicated) {
|
|
3011
|
+
if (ComponentClass === NetworkIdentity) continue;
|
|
3012
|
+
const live = world.getComponent(entity_id, ComponentClass);
|
|
3013
|
+
if (live === undefined) continue;
|
|
3014
|
+
|
|
3015
|
+
scratch.position = 0;
|
|
3016
|
+
this.binary_registry.getAdapter(ComponentClass.typeName).serialize(scratch, live);
|
|
3017
|
+
this.#prediction_history.record(entity_id, frame, desc.interp_type_id, scratch.raw_bytes, scratch.position);
|
|
3018
|
+
}
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
|
|
3022
|
+
/**
|
|
3023
|
+
* Client, start of step: reconcile every queued authoritative state.
|
|
3024
|
+
*/
|
|
3025
|
+
#apply_pending_corrections() {
|
|
3026
|
+
const pending_auth = this.#pending_auth;
|
|
3027
|
+
|
|
3028
|
+
for (const [network_id, pending] of pending_auth) {
|
|
3029
|
+
const entity_id = this.#peer.slot_table.entity_for(network_id);
|
|
3030
|
+
if (entity_id < 0 || this.#remote_entities.has(entity_id)) continue;
|
|
3031
|
+
this.#reconciled_frame.set(network_id, pending.frame);
|
|
3032
|
+
try {
|
|
3033
|
+
this.#reconcile_entity(entity_id, pending.frame, pending.parts);
|
|
3034
|
+
} catch (e) {
|
|
3035
|
+
// one entity's failure is its own: the others are corrected, and the step opens
|
|
3036
|
+
console.error(`NetworkSession: reconciling entity ${entity_id} to frame ${pending.frame} failed:`, e);
|
|
3037
|
+
}
|
|
3038
|
+
}
|
|
3039
|
+
|
|
3040
|
+
pending_auth.clear();
|
|
3041
|
+
}
|
|
3042
|
+
|
|
3043
|
+
/**
|
|
3044
|
+
* Compare the host's state of `entity_id` at `frame` with the prediction for `frame`, and where
|
|
3045
|
+
* a component differs, carry the difference into the present through its {@link Correction}.
|
|
3046
|
+
* See {@link NetworkSessionReconcile.Correct}.
|
|
3047
|
+
*
|
|
3048
|
+
* @param {number} entity_id
|
|
3049
|
+
* @param {number} frame
|
|
3050
|
+
* @param {Array<{type_id: number, bytes: Uint8Array}|null>} parts
|
|
3051
|
+
*/
|
|
3052
|
+
#reconcile_entity(entity_id, frame, parts) {
|
|
3053
|
+
const history = this.#prediction_history;
|
|
3054
|
+
const differs = this.#differs;
|
|
3055
|
+
|
|
3056
|
+
// Compare first: every part must have a prediction to compare against.
|
|
3057
|
+
let any = false;
|
|
3058
|
+
let index = 0;
|
|
3059
|
+
for (const [ComponentClass, desc] of this.#replicated) {
|
|
3060
|
+
const i = index++;
|
|
3061
|
+
differs[i] = false;
|
|
3062
|
+
|
|
3063
|
+
const part = parts[i];
|
|
3064
|
+
if (part === null || desc.correction === null) continue;
|
|
3065
|
+
|
|
3066
|
+
const type_id = desc.interp_type_id;
|
|
3067
|
+
const predicted_length = history.length(entity_id, frame, type_id);
|
|
3068
|
+
if (predicted_length < 0) {
|
|
3069
|
+
this.correction_skipped_count++;
|
|
3070
|
+
return;
|
|
3071
|
+
}
|
|
3072
|
+
|
|
3073
|
+
const predicted_bytes = history.bytes(entity_id, frame, type_id);
|
|
3074
|
+
if (bytes_equal_lengths(part.bytes, part.bytes.length, predicted_bytes, predicted_length)) continue;
|
|
3075
|
+
|
|
3076
|
+
const server = this.#scratch_of(ComponentClass, 0);
|
|
3077
|
+
const predicted = this.#scratch_of(ComponentClass, 1);
|
|
3078
|
+
this.#decode_into(ComponentClass, part.bytes, part.bytes.length, server);
|
|
3079
|
+
this.#decode_into(ComponentClass, predicted_bytes, predicted_length, predicted);
|
|
3080
|
+
|
|
3081
|
+
if (!desc.correction.same(server, predicted)) {
|
|
3082
|
+
differs[i] = true;
|
|
3083
|
+
any = true;
|
|
3084
|
+
}
|
|
3085
|
+
}
|
|
3086
|
+
|
|
3087
|
+
if (!any) return;
|
|
3088
|
+
|
|
3089
|
+
index = 0;
|
|
3090
|
+
for (const [ComponentClass, desc] of this.#replicated) {
|
|
3091
|
+
const i = index++;
|
|
3092
|
+
if (!differs[i]) continue;
|
|
3093
|
+
|
|
3094
|
+
const live = this.world.getComponent(entity_id, ComponentClass);
|
|
3095
|
+
if (live === undefined) continue;
|
|
3096
|
+
|
|
3097
|
+
const magnitude = this.#correct_component(entity_id, live, ComponentClass, desc, frame, parts[i].bytes);
|
|
3098
|
+
this.onCorrection.send4(entity_id, frame, ComponentClass, magnitude);
|
|
3099
|
+
}
|
|
3100
|
+
|
|
3101
|
+
this.correction_count++;
|
|
3102
|
+
}
|
|
3103
|
+
|
|
3104
|
+
/**
|
|
3105
|
+
* Carry the difference between the host's state and the prediction at `frame` into the live
|
|
3106
|
+
* component and into every prediction since, through the component's correction.
|
|
3107
|
+
*
|
|
3108
|
+
* @returns {number} the correction's size, as the strategy measures it
|
|
3109
|
+
*/
|
|
3110
|
+
#correct_component(entity_id, live, ComponentClass, desc, frame, server_bytes) {
|
|
3111
|
+
const history = this.#prediction_history;
|
|
3112
|
+
const type_id = desc.interp_type_id;
|
|
3113
|
+
const correction = desc.correction;
|
|
3114
|
+
const adapter = this.binary_registry.getAdapter(ComponentClass.typeName);
|
|
3115
|
+
|
|
3116
|
+
const server = this.#scratch_of(ComponentClass, 0);
|
|
3117
|
+
const predicted = this.#scratch_of(ComponentClass, 1);
|
|
3118
|
+
this.#decode_into(ComponentClass, server_bytes, server_bytes.length, server);
|
|
3119
|
+
this.#decode_into(ComponentClass, history.bytes(entity_id, frame, type_id), history.length(entity_id, frame, type_id), predicted);
|
|
3120
|
+
|
|
3121
|
+
// the present
|
|
3122
|
+
const target = this.#correction_target;
|
|
3123
|
+
target.entity_manager = this.entity_manager;
|
|
3124
|
+
target.entity = entity_id;
|
|
3125
|
+
target.component = live;
|
|
3126
|
+
target.interpolation = this.#interpolation;
|
|
3127
|
+
target.adapter = adapter;
|
|
3128
|
+
|
|
3129
|
+
let magnitude;
|
|
3130
|
+
try {
|
|
3131
|
+
magnitude = correction.apply(target, server, predicted);
|
|
3132
|
+
} finally {
|
|
3133
|
+
target.component = null;
|
|
3134
|
+
target.adapter = null;
|
|
3135
|
+
}
|
|
3136
|
+
adapter.announce(this.world, entity_id);
|
|
3137
|
+
|
|
3138
|
+
// the predictions: the host's at `frame`, and the difference carried into each since
|
|
3139
|
+
history.record(entity_id, frame, type_id, server_bytes, server_bytes.length);
|
|
3140
|
+
|
|
3141
|
+
const state = this.#scratch_of(ComponentClass, 2);
|
|
3142
|
+
const buffer = this.#scratch_send_buf;
|
|
3143
|
+
const latest = this.#local_frame - 1;
|
|
3144
|
+
for (let f = frame + 1; f <= latest; f++) {
|
|
3145
|
+
const held_length = history.length(entity_id, f, type_id);
|
|
3146
|
+
if (held_length < 0) continue;
|
|
3147
|
+
this.#decode_into(ComponentClass, history.bytes(entity_id, f, type_id), held_length, state);
|
|
3148
|
+
correction.carry(state, server, predicted);
|
|
3149
|
+
buffer.position = 0;
|
|
3150
|
+
adapter.serialize(buffer, state);
|
|
3151
|
+
history.record(entity_id, f, type_id, buffer.raw_bytes, buffer.position);
|
|
3152
|
+
}
|
|
3153
|
+
|
|
3154
|
+
return magnitude;
|
|
3155
|
+
}
|
|
3156
|
+
|
|
2154
3157
|
#wire_client_predict_reconcile() {
|
|
2155
3158
|
// Rewind doesn't go through executor.execute, so the
|
|
2156
3159
|
// before_execute normalize hook misses it. Catch it here.
|
|
2157
3160
|
this.#client.onBeforeReconcile.add(() => this.normalize_if_dirty());
|
|
2158
3161
|
|
|
2159
|
-
// Predict: run the sampler,
|
|
2160
|
-
//
|
|
3162
|
+
// Predict: run the sampler, record each action's bytes so the replay path can re-execute
|
|
3163
|
+
// without re-sampling, and execute the action as those bytes say — as the host will apply
|
|
3164
|
+
// it, rounding included. Executed as sampled, a field the wire rounds (a Float32 speed)
|
|
3165
|
+
// would predict a little differently from the host every frame.
|
|
2161
3166
|
this.#client.onPredict.add((frame, _input_writer) => {
|
|
2162
3167
|
if (this.#input_sampler === null) return;
|
|
2163
3168
|
const actions = this.#input_sampler(frame);
|
|
@@ -2171,7 +3176,10 @@ export class NetworkSession {
|
|
|
2171
3176
|
action.serialize(scratch);
|
|
2172
3177
|
const bytes = scratch.raw_bytes.slice(0, scratch.position);
|
|
2173
3178
|
recorded.push({ type_id, bytes });
|
|
2174
|
-
this.#
|
|
3179
|
+
if (!this.#execute_recorded(type_id, bytes)) {
|
|
3180
|
+
// not a registered action: executed as it is, for the executor to say so
|
|
3181
|
+
this.#client.executor.execute(action, this.local_peer_id);
|
|
3182
|
+
}
|
|
2175
3183
|
}
|
|
2176
3184
|
this.#sampled_actions_per_frame.set(frame, recorded);
|
|
2177
3185
|
this.#trim_sampled_action_ledger();
|
|
@@ -2183,19 +3191,7 @@ export class NetworkSession {
|
|
|
2183
3191
|
const recorded = this.#sampled_actions_per_frame.get(frame);
|
|
2184
3192
|
if (!recorded) return;
|
|
2185
3193
|
for (const { type_id, bytes } of recorded) {
|
|
2186
|
-
|
|
2187
|
-
if (klass === undefined) continue;
|
|
2188
|
-
const action = this.#peer.action_registry.acquire(klass);
|
|
2189
|
-
const scratch = this.#scratch_interp_buf;
|
|
2190
|
-
scratch.position = 0;
|
|
2191
|
-
scratch.writeBytes(bytes, 0, bytes.length);
|
|
2192
|
-
scratch.position = 0;
|
|
2193
|
-
action.deserialize(scratch);
|
|
2194
|
-
try {
|
|
2195
|
-
this.#client.executor.execute(action, this.local_peer_id);
|
|
2196
|
-
} finally {
|
|
2197
|
-
this.#peer.action_registry.release(action);
|
|
2198
|
-
}
|
|
3194
|
+
this.#execute_recorded(type_id, bytes);
|
|
2199
3195
|
}
|
|
2200
3196
|
});
|
|
2201
3197
|
|
|
@@ -2209,10 +3205,36 @@ export class NetworkSession {
|
|
|
2209
3205
|
if (live === undefined) continue;
|
|
2210
3206
|
const adapter = this.binary_registry.getAdapter(ComponentClass.typeName);
|
|
2211
3207
|
adapter.deserialize(buffer, live);
|
|
3208
|
+
adapter.announce(this.world, local);
|
|
2212
3209
|
}
|
|
2213
3210
|
});
|
|
2214
3211
|
}
|
|
2215
3212
|
|
|
3213
|
+
/**
|
|
3214
|
+
* Execute the action `bytes` encode, as this client's own.
|
|
3215
|
+
* @param {number} type_id
|
|
3216
|
+
* @param {Uint8Array} bytes
|
|
3217
|
+
* @returns {boolean} false when no action is registered under `type_id`
|
|
3218
|
+
*/
|
|
3219
|
+
#execute_recorded(type_id, bytes) {
|
|
3220
|
+
const klass = this.#peer.action_registry.klass_for(type_id);
|
|
3221
|
+
if (klass === undefined) return false;
|
|
3222
|
+
|
|
3223
|
+
const action = this.#peer.action_registry.acquire(klass);
|
|
3224
|
+
try {
|
|
3225
|
+
const scratch = this.#scratch_interp_buf;
|
|
3226
|
+
scratch.position = 0;
|
|
3227
|
+
scratch.writeBytes(bytes, 0, bytes.length);
|
|
3228
|
+
scratch.position = 0;
|
|
3229
|
+
action.deserialize(scratch);
|
|
3230
|
+
this.#client.executor.execute(action, this.local_peer_id);
|
|
3231
|
+
} finally {
|
|
3232
|
+
this.#peer.action_registry.release(action);
|
|
3233
|
+
}
|
|
3234
|
+
|
|
3235
|
+
return true;
|
|
3236
|
+
}
|
|
3237
|
+
|
|
2216
3238
|
#trim_sampled_action_ledger() {
|
|
2217
3239
|
const action_log = this.#peer.action_log;
|
|
2218
3240
|
if (action_log === undefined) return;
|
|
@@ -2223,73 +3245,241 @@ export class NetworkSession {
|
|
|
2223
3245
|
}
|
|
2224
3246
|
|
|
2225
3247
|
// ----------------------------------------------------------------
|
|
2226
|
-
// Internal: interpolation
|
|
3248
|
+
// Internal: interpolation — the network timeline, and each entity's role on it
|
|
2227
3249
|
// ----------------------------------------------------------------
|
|
2228
3250
|
|
|
3251
|
+
/**
|
|
3252
|
+
* The interpolands of the replicated components that are blended, in `#replicated` order. One
|
|
3253
|
+
* given to the deprecated {@link replicate} as a bare blend is built here, recorded in the
|
|
3254
|
+
* component's replication layout under its replication type id.
|
|
3255
|
+
*
|
|
3256
|
+
* @returns {Interpoland[]}
|
|
3257
|
+
*/
|
|
3258
|
+
#build_interpolands() {
|
|
3259
|
+
const out = [];
|
|
3260
|
+
const taken = new Map();
|
|
3261
|
+
|
|
3262
|
+
for (const [ComponentClass, desc] of this.#replicated) {
|
|
3263
|
+
if (desc.interpoland === null && desc.interpolator !== null) {
|
|
3264
|
+
desc.interpoland = new Interpoland(
|
|
3265
|
+
desc.interp_type_id,
|
|
3266
|
+
ComponentClass,
|
|
3267
|
+
this.binary_registry.getAdapter(ComponentClass.typeName),
|
|
3268
|
+
desc.interpolator,
|
|
3269
|
+
);
|
|
3270
|
+
}
|
|
3271
|
+
|
|
3272
|
+
const interpoland = desc.interpoland;
|
|
3273
|
+
if (interpoland === null) continue;
|
|
3274
|
+
|
|
3275
|
+
const other = taken.get(interpoland.type_id);
|
|
3276
|
+
if (other !== undefined) {
|
|
3277
|
+
throw new Error(
|
|
3278
|
+
`NetworkSession.start: ${ComponentClass.typeName ?? ComponentClass.name} and ${other.typeName ?? other.name} are interpolated ` +
|
|
3279
|
+
`under the same interpoland type_id ${interpoland.type_id}; their records would be read for each other. Give each its own.`,
|
|
3280
|
+
);
|
|
3281
|
+
}
|
|
3282
|
+
taken.set(interpoland.type_id, ComponentClass);
|
|
3283
|
+
|
|
3284
|
+
out.push(interpoland);
|
|
3285
|
+
}
|
|
3286
|
+
|
|
3287
|
+
return out;
|
|
3288
|
+
}
|
|
3289
|
+
|
|
3290
|
+
/**
|
|
3291
|
+
* The network moved `entity_id` somewhere its own simulation did not take it — a resync. On
|
|
3292
|
+
* the local timeline, show it there at once rather than blend across the gap. (An entity on
|
|
3293
|
+
* the network playout is drawn from the playout's own history, which the move does not touch.)
|
|
3294
|
+
* @param {number} entity_id
|
|
3295
|
+
*/
|
|
3296
|
+
#note_moved(entity_id) {
|
|
3297
|
+
const interpolated = this.world.getComponent(entity_id, Interpolated);
|
|
3298
|
+
if (interpolated !== undefined && interpolated.sourceId === INTERPOLATION_SOURCE_LOCAL) {
|
|
3299
|
+
interpolated.snap = true;
|
|
3300
|
+
}
|
|
3301
|
+
}
|
|
3302
|
+
|
|
3303
|
+
/**
|
|
3304
|
+
* Bring every queued entity's {@link Interpolated} in line with what the entity is to this
|
|
3305
|
+
* session. Entities that cannot be decided yet (no network id, or not yet carrying what they
|
|
3306
|
+
* interpolate) stay queued.
|
|
3307
|
+
*/
|
|
3308
|
+
#apply_pending_interpolation() {
|
|
3309
|
+
const pending = this.#interpolation_pending;
|
|
3310
|
+
|
|
3311
|
+
if (pending.size === 0 || this.#interpolation === null) {
|
|
3312
|
+
return;
|
|
3313
|
+
}
|
|
3314
|
+
|
|
3315
|
+
for (const entity_id of pending) {
|
|
3316
|
+
if (this.#assign_interpolation(entity_id)) {
|
|
3317
|
+
pending.delete(entity_id);
|
|
3318
|
+
}
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3321
|
+
|
|
3322
|
+
/**
|
|
3323
|
+
* The role decides the timeline. The host simulates every entity, and a client simulates the
|
|
3324
|
+
* ones it owns (it predicts them): those are blended on the local fixed-step timeline, keyed by
|
|
3325
|
+
* entity. Everything else on a client is written by the network and blended on the network
|
|
3326
|
+
* playout, keyed by `network_id`.
|
|
3327
|
+
*
|
|
3328
|
+
* An `Interpolated` the game attached itself is adapted rather than replaced: it keeps any
|
|
3329
|
+
* interpoland of its own for a component the session does not interpolate, and hands the ones
|
|
3330
|
+
* the session does over to the session's (two interpolands on one component would each take
|
|
3331
|
+
* the other's blend for the truth).
|
|
3332
|
+
*
|
|
3333
|
+
* @param {number} entity_id
|
|
3334
|
+
* @returns {boolean} true when the entity is settled and can leave the queue
|
|
3335
|
+
*/
|
|
3336
|
+
#assign_interpolation(entity_id) {
|
|
3337
|
+
const world = this.world;
|
|
3338
|
+
|
|
3339
|
+
if (!world.entityExists(entity_id)) {
|
|
3340
|
+
this.#attached_interpolated.delete(entity_id);
|
|
3341
|
+
return true;
|
|
3342
|
+
}
|
|
3343
|
+
|
|
3344
|
+
const identity = world.getComponent(entity_id, NetworkIdentity);
|
|
3345
|
+
|
|
3346
|
+
if (identity === undefined || identity === null) {
|
|
3347
|
+
// no longer networked: take back what we attached
|
|
3348
|
+
const ours = this.#attached_interpolated.get(entity_id);
|
|
3349
|
+
if (ours !== undefined) {
|
|
3350
|
+
this.#attached_interpolated.delete(entity_id);
|
|
3351
|
+
if (world.getComponent(entity_id, Interpolated) === ours) {
|
|
3352
|
+
world.removeComponentFromEntity(entity_id, Interpolated);
|
|
3353
|
+
}
|
|
3354
|
+
}
|
|
3355
|
+
return true;
|
|
3356
|
+
}
|
|
3357
|
+
|
|
3358
|
+
if (identity.network_id < 0) {
|
|
3359
|
+
return false; // not allocated yet
|
|
3360
|
+
}
|
|
3361
|
+
|
|
3362
|
+
// `#remote_entities` means "not owned here" on either role, but only a client plays anything
|
|
3363
|
+
// out from the network: the host simulates every entity, the ones its clients own included.
|
|
3364
|
+
const remote = this.role === NetworkSessionRole.Client && this.#remote_entities.has(entity_id);
|
|
3365
|
+
|
|
3366
|
+
const session_interpolands = this.#interpolands;
|
|
3367
|
+
|
|
3368
|
+
if (session_interpolands.length === 0) {
|
|
3369
|
+
return true;
|
|
3370
|
+
}
|
|
3371
|
+
|
|
3372
|
+
let carries_any = false;
|
|
3373
|
+
for (let i = 0; i < session_interpolands.length; i++) {
|
|
3374
|
+
if (world.getComponent(entity_id, session_interpolands[i].component_class) !== undefined) {
|
|
3375
|
+
carries_any = true;
|
|
3376
|
+
break;
|
|
3377
|
+
}
|
|
3378
|
+
}
|
|
3379
|
+
if (!carries_any) {
|
|
3380
|
+
return false; // e.g. an initial sync that has attached the identity but not the transform yet
|
|
3381
|
+
}
|
|
3382
|
+
|
|
3383
|
+
const source_id = remote ? this.#interp_source_id : INTERPOLATION_SOURCE_LOCAL;
|
|
3384
|
+
|
|
3385
|
+
const key = remote ? identity.network_id : entity_id;
|
|
3386
|
+
|
|
3387
|
+
let interpolated = world.getComponent(entity_id, Interpolated);
|
|
3388
|
+
|
|
3389
|
+
if (interpolated === undefined) {
|
|
3390
|
+
interpolated = new Interpolated();
|
|
3391
|
+
interpolated.interpolands = session_interpolands.slice();
|
|
3392
|
+
interpolated.sourceId = source_id;
|
|
3393
|
+
interpolated.key = key;
|
|
3394
|
+
world.addComponentToEntity(entity_id, interpolated);
|
|
3395
|
+
this.#attached_interpolated.set(entity_id, interpolated);
|
|
3396
|
+
return true;
|
|
3397
|
+
}
|
|
3398
|
+
|
|
3399
|
+
if (interpolated.sourceId === source_id && interpolated.key === key
|
|
3400
|
+
&& session_interpolands.every(ip => interpolated.interpolands.includes(ip))) {
|
|
3401
|
+
return true; // already in line
|
|
3402
|
+
}
|
|
3403
|
+
|
|
3404
|
+
// Only ever called as a step opens, when no render blend is in the live components, so the
|
|
3405
|
+
// interpolands can be swapped without one being left behind as the truth.
|
|
3406
|
+
const kept = interpolated.interpolands.filter(
|
|
3407
|
+
ip => !session_interpolands.some(own => own.component_class === ip.component_class)
|
|
3408
|
+
);
|
|
3409
|
+
interpolated.interpolands = kept.concat(session_interpolands);
|
|
3410
|
+
interpolated.sourceId = source_id;
|
|
3411
|
+
interpolated.key = key;
|
|
3412
|
+
|
|
3413
|
+
return true;
|
|
3414
|
+
}
|
|
3415
|
+
|
|
2229
3416
|
/**
|
|
2230
3417
|
* Record post-apply state for every remote-owned entity into the
|
|
2231
|
-
*
|
|
2232
|
-
* interpolated, so they're skipped.
|
|
3418
|
+
* network timeline. Locally-owned entities are predicted, not
|
|
3419
|
+
* interpolated from the network, so they're skipped.
|
|
2233
3420
|
*
|
|
2234
3421
|
* Doesn't fire on the host — the replicator's deferral path doesn't
|
|
2235
3422
|
* emit `onFrameApplied`, so the host gets no recording naturally.
|
|
2236
3423
|
*/
|
|
2237
3424
|
#on_frame_applied(_peer_id, frame_number) {
|
|
2238
|
-
this.#interp_log
|
|
3425
|
+
const log = this.#interp_log;
|
|
3426
|
+
const interpolands = this.#interpolands;
|
|
3427
|
+
|
|
3428
|
+
log.begin_tick(frame_number);
|
|
2239
3429
|
for (const entity_id of this.#remote_entities) {
|
|
2240
3430
|
const identity = this.world.getComponent(entity_id, NetworkIdentity);
|
|
2241
3431
|
if (identity === undefined || identity.network_id < 0) continue;
|
|
2242
|
-
for (
|
|
2243
|
-
|
|
2244
|
-
const live = this.world.getComponent(entity_id,
|
|
3432
|
+
for (let i = 0; i < interpolands.length; i++) {
|
|
3433
|
+
const interpoland = interpolands[i];
|
|
3434
|
+
const live = this.world.getComponent(entity_id, interpoland.component_class);
|
|
2245
3435
|
if (live === undefined) continue;
|
|
2246
|
-
const
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
this.#interp_log.end_record();
|
|
3436
|
+
const buffer = log.begin_record(identity.network_id, interpoland.type_id);
|
|
3437
|
+
interpoland.serialization_adapter.serialize(buffer, live);
|
|
3438
|
+
log.end_record();
|
|
2250
3439
|
}
|
|
2251
3440
|
}
|
|
2252
|
-
|
|
3441
|
+
log.end_tick();
|
|
3442
|
+
|
|
3443
|
+
// hold the whole render delay's worth of frames, however many entities a frame carries
|
|
3444
|
+
log.ensure_ticks(PLAYOUT_HISTORY_FRAMES);
|
|
2253
3445
|
|
|
2254
|
-
this.#playout.record_arrival(
|
|
3446
|
+
this.#playout.record_arrival(this.#clock_ms, frame_number);
|
|
2255
3447
|
}
|
|
2256
3448
|
|
|
2257
3449
|
/**
|
|
2258
|
-
*
|
|
2259
|
-
* interpolated bytes into each remote-owned entity's live
|
|
2260
|
-
* components. Sets `render_dirty` if anything was written.
|
|
3450
|
+
* The network timeline's window for this render frame.
|
|
2261
3451
|
*
|
|
2262
|
-
*
|
|
2263
|
-
*
|
|
3452
|
+
* A frame reaches the log only if it carried actions for this peer, and a frame that carried
|
|
3453
|
+
* none is one in which nothing replicated changed. So the value at a frame the log does not
|
|
3454
|
+
* hold is the value at the last one before it that it does: blend from that frame, and to the
|
|
3455
|
+
* next frame if it is held, otherwise hold still. Blending only between adjacent frames instead
|
|
3456
|
+
* would treat an unchanged frame as unknown and show the newest state early, then hold.
|
|
3457
|
+
*
|
|
3458
|
+
* @returns {{tick_a:number, tick_b:number, t:number}}
|
|
2264
3459
|
*/
|
|
2265
|
-
#
|
|
2266
|
-
|
|
2267
|
-
|
|
3460
|
+
#sample_playout() {
|
|
3461
|
+
const w = this.#playout.window(this.#clock_ms);
|
|
3462
|
+
const out = this.#playout_window;
|
|
3463
|
+
const log = this.#interp_log;
|
|
2268
3464
|
|
|
2269
|
-
const
|
|
3465
|
+
const a = log.latest_tick_at_or_before(w.tick_a);
|
|
2270
3466
|
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
scratch.position = 0;
|
|
2281
|
-
const ok = this.#interp_log.interpolate(
|
|
2282
|
-
scratch, identity.network_id, desc.interp_type_id,
|
|
2283
|
-
tick_a, tick_b, t, desc.interp,
|
|
2284
|
-
);
|
|
2285
|
-
if (!ok) continue;
|
|
2286
|
-
scratch.position = 0;
|
|
2287
|
-
const adapter = this.binary_registry.getAdapter(ComponentClass.typeName);
|
|
2288
|
-
adapter.deserialize(scratch, live);
|
|
2289
|
-
wrote_anything = true;
|
|
2290
|
-
}
|
|
3467
|
+
if (a < 0) {
|
|
3468
|
+
// The playhead is before anything the log holds — the playout has not started, or it
|
|
3469
|
+
// starts before the first frame this client received (a late join). Hold on the
|
|
3470
|
+
// earliest frame held: it is what the playhead reaches first, so nothing jumps back.
|
|
3471
|
+
const oldest = log.oldest_tick();
|
|
3472
|
+
out.tick_a = oldest;
|
|
3473
|
+
out.tick_b = oldest;
|
|
3474
|
+
out.t = 0;
|
|
3475
|
+
return out;
|
|
2291
3476
|
}
|
|
2292
|
-
|
|
3477
|
+
|
|
3478
|
+
out.tick_a = a;
|
|
3479
|
+
out.tick_b = log.has_tick(w.tick_b) ? w.tick_b : a;
|
|
3480
|
+
out.t = w.t;
|
|
3481
|
+
|
|
3482
|
+
return out;
|
|
2293
3483
|
}
|
|
2294
3484
|
|
|
2295
3485
|
// ----------------------------------------------------------------
|