Skip to content

Latest commit

 

History

History
504 lines (490 loc) · 130 KB

coverage.md

File metadata and controls

504 lines (490 loc) · 130 KB

Coverage

What the safe API binds and which tests check it; then which tests check the magnitude rules of oxijolt::limits, and what they leave open. limits.md derives the bounds themselves. Test names refer to the integration tests in crates/oxijolt/tests and the unit tests in crates/oxijolt/src (src/... below). Line numbers refer to the vendored Jolt 5.6 sources (crates/oxijolt-sys/vendor/JoltPhysics/Jolt/Physics/).

What is bound and tested

Feature Safe API Tests
World with settings and validation PhysicsWorld::new, WorldSettings world.rs: default_world_steps, invalid_settings_are_rejected, gravity_round_trips_including_zero
Solver step counts per world WorldSettings::velocity_steps, position_steps, PhysicsWorld::velocity_steps, position_steps solver_steps.rs: step_counts_outside_jolts_range_are_refused, step_counts_read_back_from_jolt, a_stack_without_position_steps_stays_finite, fewer_solver_steps_let_a_hinge_chain_stretch_more, chain_at_four_steps_is_identical_with_1_and_4_workers; src/world/tests.rs: world_settings_leave_every_other_physics_setting_at_jolts_default
Contact tuning per world WorldSettings::penetration_slop, speculative_contact_distance, PhysicsWorld::penetration_slop, speculative_contact_distance contact_tuning.rs: contact_distances_outside_their_range_are_refused, contact_distances_read_back_from_jolt, a_deep_impact_is_corrected_down_to_the_slop, a_gently_placed_sphere_rests_within_the_slop_not_at_it, speculative_contacts_reach_bodies_within_the_distance, contact_distances_at_their_bounds_keep_a_small_scene_finite, far_bodies_within_the_speculative_distance_stay_finite, tuned_stacks_are_identical_with_1_and_4_workers; src/world/tests.rs: contact_distances_are_validated, world_settings_leave_every_other_physics_setting_at_jolts_default
Step with a report of dropped work, time step bounds, collision steps per update PhysicsWorld::step, step_with_collision_steps, StepReport, StepError, MIN_DELTA_TIME, MAX_DELTA_TIME, MAX_COLLISION_STEPS world.rs: step_rejects_bad_delta_time, step_rejects_delta_time_below_the_bound, step_rejects_delta_time_above_the_bound, full_contact_constraint_buffer_is_reported_and_the_world_advances, full_body_pair_cache_is_reported_and_the_world_advances; collision_steps.rs: collision_step_counts_outside_the_bound_are_refused, bad_total_delta_times_are_refused_for_every_count, collision_steps_shorter_than_min_delta_time_are_refused, a_refused_call_consumes_nothing, a_refused_call_keeps_the_queued_events, collision_steps_cover_the_whole_delta_time, the_collision_step_count_reaches_jolt, a_rigid_force_acts_over_all_collision_steps_and_clears_after_the_call, a_soft_body_force_acts_in_the_first_collision_step_only, a_vehicle_gravity_override_acts_like_world_gravity_in_every_collision_step, one_collision_step_equals_step, sub_stepped_events_come_in_one_canonical_batch; job_system.rs: a_saturated_update_at_max_collision_steps_fits_jolts_job_pool; the doctest of step_with_collision_steps
Crate-wide error and result, outside the crate root oxijolt::error::Error, oxijolt::error::Result, From for every area error src/error/tests.rs: every_area_error_converts_into_its_variant, display_is_the_wrapped_errors, source_is_the_wrapped_errors_source, sources_are_reported, error_is_send_sync_static_and_copy; root_glob.rs: the_crate_root_leaves_result_and_error_to_other_globs, the_crate_wide_result_is_named_by_the_error_module; the doctest of Error
Prelude next to an engine prelude that exports Vec3, Quat, Real and Result oxijolt::prelude, oxijolt::prelude::math prelude.rs: the_prelude_leaves_math_and_result_to_the_engine_prelude, the_math_types_come_from_the_prelude_math_module; the doctest of prelude
The trait rules of the API guidelines (R6, R7) ids, area errors, settings and their Default api_traits.rs: ids_compare_order_and_hash, errors_are_copy_and_comparable, settings_are_clone_and_comparable, settings_without_required_inputs_have_defaults (compile-time)
Collision layers CollisionLayers, ObjectLayer, BroadPhaseLayer dynamics.rs: collision_layers_decide_which_bodies_touch; src/layers.rs: validate_rejects_inconsistent_tables
Several worlds, threads PhysicsWorld: Send + Sync, WorldSettings::worker_threads dynamics.rs: two_worlds_side_by_side_do_not_interfere, worlds_step_in_parallel_threads; world.rs: world_and_shape_are_send_and_sync, world_is_readable_from_many_threads
Caller and single-threaded job systems JobSystem, Job, WorldSettings::job_system, WorldSettings::MAX_CONCURRENCY, WorldSettings::single_threaded job_system.rs: rayon_job_system_matches_the_native_pool, inline_job_system_matches_the_native_pool, step_from_the_only_thread_of_a_rayon_pool_completes, jobs_may_outlive_their_world, a_deferred_job_may_finish_on_another_thread_while_the_world_drops, a_job_system_that_keeps_every_job_does_not_run_out_of_jolt_jobs, a_panicking_job_system_panics_out_of_step_and_the_world_stays_usable, max_concurrency_is_bounded, worlds_sharing_one_job_system_step_in_parallel, the_last_of_job_system_and_worker_threads_wins, a_sleeping_world_queues_no_jobs, single_threaded_matches_the_native_pool, the_last_of_three_job_system_choices_wins, a_single_threaded_world_steps_on_another_thread, worlds_with_different_native_job_systems_step_in_parallel; src/world/tests.rs: single_threaded_is_chosen_last_wins_and_has_concurrency_one; src/job_system.rs: run_and_drop_each_run_the_job_once, jobs_run_inside_a_queue_callback_wait_for_the_end_of_the_update, a_job_released_by_its_update_does_nothing_when_run_later, concurrent_panics_keep_one_payload_and_drop_the_others; job_system_leaks.rs: caller_job_systems_do_not_leak; the Rayon doctest of JobSystem
Static, kinematic and dynamic bodies, ids BodySettings, create_body, BodyId bodies.rs: ids_follow_insertion_order, foreign_and_stale_ids_are_rejected, invalid_body_settings_are_rejected, full_world_rejects_another_body
Every body of a world, in id order PhysicsWorld::body_ids, contains_body bodies.rs: body_ids_list_every_body_in_id_order (after a removal and an index reuse, with a character's inner body); world.rs: ids_are_iterators; the playground's digest tests (examples/playground/src/digest.rs)
Pose and velocity, read and write BodyRef, BodyMut, Activation bodies.rs: pose_and_velocity_read_back_as_exact_bits, activation_decides_whether_a_pose_write_wakes_the_body
Forces, torque, reset BodyMut::add_force, add_force_at_point, add_torque, reset_forces bodies.rs: forces, reset_forces_ignores_static_and_kinematic_bodies
Sleeping and active state BodyRef::is_sleeping, is_active bodies.rs: sleeping_flag_is_readable
Poses of every awake body, in BodyId order PhysicsWorld::active_body_poses, active_body_poses_into, BodyPose src/body/poses/tests.rs: poses_come_in_body_id_order_whatever_order_jolt_woke_them, poses_match_the_per_body_readout_bit_for_bit, poses_into_clears_and_reuses_the_buffer, each_call_reads_the_awake_set_again_into_the_same_buffer, a_world_with_only_soft_bodies_awake_reads_them, bodies_that_fall_asleep_are_synced_through_their_deactivation_event, concurrent_shared_reads_and_saves_agree; body_poses.rs: poses_are_identical_across_thread_counts, poses_are_identical_with_caller_job_systems
Impulses BodyMut::add_impulse, add_angular_impulse, add_impulse_at_point body_controls.rs: impulses_change_velocity_at_once_and_wake, impulse_at_point_spins_the_body, impulses_respect_locked_axes, impulses_ignore_static_and_kinematic_bodies_and_refuse_soft_bodies
Buoyancy and drag BodyMut::apply_buoyancy_impulse, BuoyancySettings, extension JPH_Body_GetSubmergedVolume, JPH_Body_ApplyBuoyancyImpulse2 buoyancy.rs: a_light_box_floats_at_its_density_line, a_sphere_twice_as_light_floats_half_under, a_dense_box_sinks_to_the_floor, drag_slows_a_submerged_body, drag_never_reverses_a_body_in_one_call, a_current_leaves_a_body_exactly_at_rest_in_zero_gravity, a_current_carries_a_floating_body, the_buoyant_lever_matches_the_geometry, a_fully_submerged_offset_body_turns, velocities_are_clamped_right_after_the_call, locked_axes_stay_still, only_submerged_dynamic_bodies_are_pushed; body_ext_smoke.rs (raw); helpers_determinism.rs: helpers_match_across_processes, a_rollback_replays_buoyancy_queries_and_estimates_exactly; helpers_leaks.rs
Kinematic moves BodyMut::move_kinematic body_controls.rs: a_kinematic_platform_moves_toward_its_target, a_kinematic_move_keeps_its_velocity_after_the_step, a_tiny_move_does_not_wake_a_sleeping_kinematic_body, kinematic_moves_respect_locked_axes, a_kinematic_platform_carries_a_resting_cube
Activation on demand BodyMut::activate, deactivate, PhysicsWorld::activate_bodies_in_box body_controls.rs: deactivate_zeroes_velocities_and_reports_an_event, deactivate_zeroes_the_velocities_of_a_body_already_asleep, repeated_deactivation_reports_once, activate_wakes_a_sleeping_body_and_reports_it, deactivate_refuses_soft_bodies, activate_bodies_in_box_wakes_exact_overlaps_in_body_id_order; src/body/tests.rs: the_broad_phase_box_encloses_the_callers_box
Sensors BodySettings::sensor, BodyRef::is_sensor sensors.rs: a_sensor_reports_a_falling_cube_without_stopping_it, a_listener_cannot_turn_a_sensor_contact_into_an_ordinary_one, a_kinematic_body_entering_a_static_sensor_is_reported, a_static_sensor_loses_a_body_that_falls_asleep, an_active_kinematic_sensor_sees_a_sleeping_body, sensors_never_fall_asleep, a_deactivated_sensor_does_not_see_a_sleeping_body, an_awake_body_still_triggers_a_deactivated_sensor, a_character_inner_body_triggers_a_sensor, a_soft_body_reports_a_sensor
User data BodySettings::user_data, BodyRef::user_data body_settings.rs: user_data_round_trips, ragdoll_parts_refuse_user_data, changing_settings_after_creation_changes_no_body
Locked axes BodySettings::allowed_dofs, BodyRef::allowed_dofs, AllowedDofs, BodyError::RestrictedDofs body_settings.rs: a_plane_2d_body_stays_in_its_plane, axes_stay_world_axes_for_a_rotated_body, allowed_dofs_read_back, bodies_with_restricted_dofs_are_refused_by_every_constraint_kind_vehicles_and_ragdolls, rotated_rebase_refuses_restricted_dofs_and_changes_nothing, translation_rebase_keeps_restricted_dofs; src/body/tests.rs: allowed_dofs_match_jolts_flags
Movement capability and motion type changes BodySettings::allow_dynamic_or_kinematic, BodyRef::can_be_kinematic_or_dynamic, BodyMut::set_motion_type, BodyError::CannotMove body_structure.rs: a_static_body_that_may_move_falls_when_made_dynamic, a_static_body_without_the_flag_cannot_move, making_a_body_static_stops_and_deactivates_it, dynamic_to_kinematic_drops_forces, same_motion_type_changes_nothing, motion_type_changes_refuse_owned_bodies, removing_the_constraint_releases_the_guard, a_static_body_that_may_move_joins_a_fixed_constraint_with_an_automatic_point
Shape changes BodyMut::set_shape shape_changes.rs: set_shape_gives_the_mass_properties_of_a_fresh_body, set_shape_with_the_same_shape_and_a_new_mass_changes_the_mass_and_refuses_earlier_states, set_shape_with_none_restores_the_shapes_own_mass, set_shape_keeps_the_origin_and_moves_the_centre_of_mass, set_shape_keeps_the_allowed_dofs, a_growing_shape_pushes_a_resting_cube_up, a_shrinking_static_floor_wakes_the_cube_on_it, set_shape_wakes_bodies_between_old_and_new_bounds, set_shape_wakes_the_same_bodies_whether_or_not_the_broad_phase_was_optimized, set_shape_refuses_owned_bodies, a_dropped_shape_lives_on_in_its_body; body_controls_leaks.rs: body_controls_do_not_leak
Body controls replay the controls above with save_state and restore_state body_controls_state.rs: momentary_inputs_replay_after_a_detour, the_inputs_change_the_run, creation_only_configuration_survives_detours_and_structural_edits, shape_and_motion_type_changes_refuse_earlier_states, restore_after_deactivate_reports_no_activation_event; body_controls_determinism.rs: controls_match_with_1_and_4_workers, controls_match_across_processes; the compile_fail examples of docs/bodies.md
Removal wakes the bodies around it PhysicsWorld::remove_body bodies.rs: removal_wakes_bodies_resting_on_it, removal_wakes_the_same_bodies_whether_or_not_the_broad_phase_was_optimized
Mass override, continuous collision, gravity factor BodySettings::mass, motion_quality, gravity_factor bodies.rs: forces, mass_too_small_to_invert_is_rejected, gravity_factor_scales_the_fall; dynamics.rs: linear_cast_body_does_not_tunnel_through_thin_static
Provided mass and inertia, the shape's ignored BodySettings::mass_and_inertia, Inertia src/body/tests.rs: provided_principal_inertia_reaches_the_motion_properties, provided_tensor_inertia_reaches_the_motion_properties; body_settings.rs: provided_inertia_spins_the_body_as_given, invalid_provided_inertia_is_refused, the_last_mass_setter_wins, set_shape_recomputes_provided_inertia_from_the_shape, provided_inertia_at_its_bounds_steps_finitely; ragdoll.rs: provided_inertia_on_a_ragdoll_part; vehicle.rs: a_chassis_with_provided_inertia_drives_finitely; api_traits.rs: settings_are_clone_and_comparable; the doctest of mass_and_inertia
Damping, mass readout BodySettings::linear_damping, angular_damping, BodyRef::mass src/body.rs: damping_reaches_the_body, invalid_damping_is_rejected, mass_is_reported_for_dynamic_bodies_only; ragdoll.rs: plain_settings_keep_the_masses_and_stabilized_ones_the_total
Contacts of the last step PhysicsWorld::were_bodies_in_contact ragdoll.rs: the_same_parts_as_plain_bodies_collide, two_ragdolls_collide_with_each_other_but_not_with_themselves; listeners.rs: added_and_persisted_pairs_were_in_contact
Enhanced internal edge removal BodySettings::enhanced_internal_edge_removal src/body.rs: enhanced_internal_edge_removal_reaches_the_body (reads the flag back from the Jolt body); dynamics.rs: enhanced_internal_edge_removal_smooths_sliding_over_a_compound
Box, sphere, Y-cylinder, Y-capsule, convex radius Shape::new_box, new_box_with_convex_radius, new_sphere, new_cylinder, new_capsule shapes.rs: sharp_box_edge_ray_hits_the_exact_corner, convex_radius_rounds_box_edges_for_contacts; src/shape.rs: cylinder_and_capsule_dimensions_reach_jolt, invalid_dimensions_are_rejected
Heightfield (n = 33, holes, block size, active-edge threshold) Shape::new_height_field, HeightFieldSettings shapes.rs: height_field_33_builds_and_matches_samples_at_nodes, height_field_rising_along_z_matches_analytic_surface, height_field_of_holes_has_no_collision, height_field_with_custom_active_edge_threshold_builds, active_edge_threshold_decides_the_normal_on_a_gentle_ridge, static_only_shapes_are_rejected_for_moving_bodies
Offset centre of mass Shape::new_offset_center_of_mass shapes.rs: low_center_of_mass_rights_a_tilted_box; src/shape.rs: offset_center_of_mass_moves_only_the_center
Compound with per-child pose and user data Shape::new_compound, CompoundChild, CompoundSubShape shapes.rs: compound_children_report_their_user_data, child_pose_is_applied, single_child_compound_keeps_its_user_data
Compound edits at run time: add, remove, move and replace children, publish shapes that set_shape installs MutableCompound, ShapeError::NoSubShape src/shape/mutable/tests.rs: to_shape_builds_what_new_compound_builds, the_holder_stays_index_aligned, removing_to_zero_and_adding_again_works, extent_is_checked_after_the_centre_of_mass_moves, mass_free_children_leave_the_centre_where_mass_puts_it; mutable_compounds.rs: removing_a_child_drops_the_cube_it_carried, wake_order_does_not_depend_on_broad_phase_optimisation, an_added_child_catches_a_falling_cube, a_moved_child_pushes_a_resting_cube_up, a_replaced_child_keeps_its_slot_user_data, later_children_move_down_after_a_removal, a_commit_reaches_only_the_body_it_is_set_on, a_dynamic_compound_losing_a_child_gets_fresh_mass_properties, commits_follow_the_body_rules_of_set_shape, editing_and_publishing_do_not_touch_the_world, a_state_before_a_commit_is_refused_and_one_after_replays_exactly, removed_contacts_after_a_commit_carry_ids_of_the_old_shape, a_character_on_a_removed_child_keeps_updating, a_committed_shape_nests_and_scales; mutable_compounds_determinism.rs: mutable_compounds_match_with_1_and_4_workers, mutable_compounds_match_across_processes, a_rollback_after_the_last_edit_replays_exactly; shape_stress.rs (the mutable family, also in the asserts leg); mutable_compounds_leaks.rs (Windows): compound_edits_do_not_leak
Convex hull Shape::new_convex_hull, new_convex_hull_with_convex_radius, new_convex_hull_with_material, ConvexHullError src/shape/hull/tests.rs: cube_corners_make_a_six_faced_hull, points_without_a_triangle_are_degenerate, points_in_one_plane_are_coplanar, hull_carries_its_material; hull_shapes.rs: irregular_rotated_hull_falls_and_rests_on_a_floor, thin_box_hull_is_a_dynamic_body, rotated_needle_hull_is_refused_as_dynamic_and_accepted_as_static, queries_hit_a_static_hull_from_above, default_hull_radius_equals_explicit, clouds_the_hull_builder_asserts_on_are_refused_or_built_without_asserts (without asserts only, see limits.md)
Triangle mesh with per-triangle materials, and the triangles it drops Shape::new_mesh, new_mesh_with_settings, MeshSettings, MeshBuildQuality, DroppedTriangles, MeshError src/shape/mesh/tests.rs: unit_quad_builds_a_mesh, triangles_carry_their_materials, mesh_settings_reach_jolt, meshes_without_usable_triangles_are_refused, dropped_triangles_are_reported_with_their_area, materials_follow_the_input_triangles_past_dropped_ones; mesh_shapes.rs: rays_follow_the_triangle_surface, shape_queries_see_the_mesh_from_above, dynamic_shapes_rest_on_a_mesh, contacts_report_the_triangle_material, thin_strips_of_a_wide_level_mesh_carry_a_cube, the_thinnest_kept_slivers_collide_with_convex_shapes_up_to_the_extent, the_smallest_kept_triangles_collide_with_convex_shapes_up_to_the_extent
Kinematic mesh bodies; meshes refused for dynamic bodies, queries, characters and ragdolls PhysicsWorld::create_body with BodySettings::mass mesh_shapes.rs: kinematic_mesh_platform_carries_a_box, kinematic_pure_mesh_steps_without_inertia, bodies_that_may_not_use_a_mesh_are_refused, meshes_and_heightfields_never_collide_with_each_other; src/shape/mesh/tests.rs: kinematic_eligibility_looks_through_compounds_and_decorators
Scaled shapes Shape::new_scaled src/shape/scaled/tests.rs: box_bounds_follow_the_scale, jolt_scale_rules_per_shape_kind, scaled_box_has_the_mass_of_the_equivalent_box, materials_survive_scaling, scaled_meshes_stay_kinematic_and_collidable, placements_match_jolts_centre_of_mass_spaces, scaled_meshes_are_checked_for_the_extent_they_were_built_for; scaled_shapes.rs: non_uniformly_scaled_hull_and_box_rest_on_a_mesh, scaled_mesh_with_a_far_centre_of_mass_carries_a_cube, mirrored_mesh_faces_the_other_way, kinematic_scaled_mesh_carries_a_box, scaled_mesh_is_refused_as_dynamic, scaled_height_field_catches_a_falling_sphere, mirrored_height_field_faces_down; oxijolt-sys shape_ext_smoke.rs (the triangle readback it uses: triangles_are_read_across_batches_up_to_the_capacity, height_field_holes_have_no_triangles, compound_and_decorated_shapes_have_no_triangles)
Tapered capsule and tapered cylinder (cone) Shape::new_tapered_capsule, new_tapered_cylinder src/shape/tapered/tests.rs: tapered_capsule_reaches_jolt, tapered_cylinder_and_cone_reach_jolt, tapered_shapes_follow_jolts_scale_rules; tapered_shapes.rs: tapered_capsule_and_cone_rest_on_a_mesh, queries_hit_tapered_shapes
Jolt's message for refused shape settings ShapeError::Rejected, oxijolt::error::JoltMessage src/error/tests.rs: shape_error_variants_display_their_payload, jolt_message_reads_up_to_the_nul, jolt_message_without_nul_is_cut_to_capacity, jolt_message_drops_a_character_cut_at_the_end; oxijolt-sys shape_ext_smoke.rs
Seeded stress of the new shapes in an asserts-safe child process (3000 sparse hulls, outside the clouds the hull builder asserts on, among them clouds with a nearly collinear spike, a nearly flat cap or near-tied extreme points, 600 meshes among them level-like grids with thin strips next to far triangles, 1200 scaled shapes, 1000 tapered shapes, a share of them collided and queried, the meshes also by a box as large as the default convex extent) the constructors above shape_stress.rs: shapes_survive_seeded_stress
Determinism and rollback of the new shapes the shapes above in one scene mesh_shapes_determinism.rs: new_shapes_run_identically_with_1_and_4_workers, rollback_after_a_detour_replays_the_straight_run
Shape cooking: shapes with children and materials to bytes and back, refused when of another build or damaged Shape::save_binary_state, Shape::restore_binary_state, BinaryStateError, ShapeError::BinaryState shape_binary_state.rs: every_shape_kind_round_trips, materials_round_trip_with_their_user_data, heightfields_without_material_indices_round_trip, a_restored_mesh_keeps_its_convex_extent, a_world_on_a_restored_mesh_steps_like_one_on_the_original, saves_in_two_processes_are_equal; src/shape/binary_state/tests.rs: the_format_version_is_the_extension_s, the_header_names_this_build, bytes_of_another_build_are_refused, every_header_bit_flip_is_refused, payload_bit_flips_are_refused_as_corrupt, every_truncation_is_refused_as_truncated, bytes_after_the_payload_are_refused, bytes_without_the_header_are_not_binary_state, a_record_joltc_refuses_behind_a_valid_checksum_is_rejected, a_restored_shape_beyond_the_extent_is_malformed, the_shape_error_reports_its_source; src/shape/binary_state/hash.rs: matches_the_reference_vectors, pieces_hash_like_the_whole; oxijolt-sys shape_state.rs (a box and a compound of a mesh and a shared hull round-trip, an empty shape keeps its centre of mass, and each record check refuses by its own message)
Leak gate for shape cooking (Windows) save and restore of a compound with a mesh, a hull and materials, a refusal by the checksum and one by joltc shape_binary_state_leaks.rs: saving_and_restoring_shapes_does_not_leak
Real models from open sources (report) Shape::new_mesh, new_convex_hull, cooking, bodies and a character on the meshes real_meshes.rs: radio, kitchen_fridge, bathtub, bookcase, track_tile, dungeon_corridor, oloid_mesh_and_hull; real_meshes_downloaded.rs (with scripts/fetch_models.py): spot, scattering_skull, scattering_skull_statue, a_changed_skull_buffer_is_refused; real_meshes_determinism.rs: track_tile_runs_identically_with_1_and_4_workers, dungeon_corridor_runs_identically_with_1_and_4_workers, skull_runs_identically_with_1_and_4_workers
Thin dynamic hulls on a floor (limits) Shape::new_convex_hull on dynamic bodies thin_hulls.rs: thin_hulls_set_down_rest_and_sleep, a_thin_dome_slapping_down_sinks_into_a_box_and_through_a_mesh
Shapes shared between bodies and worlds Shape shapes.rs: shapes_are_shared_across_bodies_and_worlds; bodies.rs: shape_can_be_dropped_after_body_creation; ragdoll.rs: humanoid_settles_on_a_heightfield_in_a_second_world (the same terrain and compound shapes in two worlds, identical ray hits)
Physics materials with user data PhysicsMaterial, Shape::new_box_with_material and its siblings, HeightFieldSettings::materials, ContactManifold::materials src/material.rs: user_data_round_trips, convex_constructors_keep_the_plain_shape_and_carry_the_material, compound_children_resolve_their_own_materials, padded_height_field_cells_resolve_their_materials, single_material_height_field_resolves_everywhere; listeners.rs: materials_are_reported_for_each_side; crates/oxijolt-sys/tests/material_smoke.rs
Ray cast PhysicsWorld::cast_ray, RayCast, RayCastHit queries.rs: ray_cast_builder_defaults, ray_hits_chunk_and_terrain_from_twenty_metres, ray_starting_inside_hits_at_exactly_zero, ray_normals_point_out_of_the_hit_surface; shapes.rs: height_field_is_hit_from_below
Shape cast PhysicsWorld::cast_shape, ShapeCast, ShapeCastHit queries.rs: capsule_cast_down_reports_floor_normal_and_distance, rotated_capsule_cast_uses_its_rotation, target_distance_stops_short, start_penetrating_is_reported_moving_in_not_out
Collide shape PhysicsWorld::collide_shape, CollideShape, CollideShapeHit queries.rs: collide_capsule_with_floor_reports_geometric_depth, collide_ceiling_normal_points_down, max_separation_reports_negative_depth
Query filters: layers, child groups, excluded body QueryFilter queries.rs: spawn_ground_ignores_canopy_by_group, object_layer_selection_skips_other_layers, excluded_body_is_skipped, nested_compound_group_governs_shape_casts_and_collide, filter_rejects_unknown_layer_and_foreign_body
Queries without a step, broad-phase optimisation PhysicsWorld::optimize_broad_phase queries.rs: queries_see_created_moved_and_removed_bodies_without_a_step, optimize_broad_phase_keeps_query_results
Queries from many threads queries on &PhysicsWorld queries.rs: filtered_queries_run_in_parallel; world.rs: rays_are_cast_from_many_threads
Floating origin PhysicsWorld::rebase rebase.rs: vehicle_drives_across_a_rotating_rebase, resting_item_stays_across_a_rebase, sleeping_body_stays_asleep_across_a_rebase, drift_rebase_equals_the_scene_built_in_the_new_frame, rays_answer_the_same_across_a_rebase, invalid_rebase_changes_nothing; ragdoll.rs: rebase_moves_a_settled_ragdoll_rigidly; constraints.rs: rebase_moves_constraints_rigidly, rebase_with_a_pulley_is_atomic, rebase_with_pulleys_is_repeatable
Same results with 1 and 4 worker threads, with caller job systems and with the single-threaded job system, also with several collision steps, for the scenes the tests run (determinism.md) WorldSettings::worker_threads, WorldSettings::job_system, WorldSettings::single_threaded, PhysicsWorld::step_with_collision_steps determinism.rs: stacks_digest_is_identical_across_thread_counts, chunk_digest_is_identical_across_thread_counts, walker_digest_is_identical_across_thread_counts, vehicle_digest_is_identical_across_thread_counts, fleet_digest_is_identical_across_thread_counts, fleet_digest_detects_a_changed_input, ragdoll_pile_digest_is_identical_across_thread_counts, constraint_digest_is_identical_across_thread_counts, soft_body_digest_is_identical_across_thread_counts, permuted_insertion_order_fails_the_gate, stacks_digest_is_identical_across_thread_counts_with_collision_steps, fleet_digest_is_identical_across_thread_counts_with_collision_steps, the nine *_digest_is_identical_with_caller_job_systems gates and the nine *_digest_is_identical_with_the_single_threaded_job_system gates; constraint_forces_determinism.rs: constraint_impulses_are_identical_with_1_and_4_workers; event_determinism.rs: events_are_identical_with_1_and_4_workers, sub_stepped_events_are_identical_with_1_and_4_workers, events_are_identical_with_caller_job_systems, events_are_identical_with_the_single_threaded_job_system, observing_every_event_leaves_the_simulation_unchanged; state.rs: rollback_replay_is_identical_across_processes; vehicle.rs: drive_a_route_twice_gives_identical_bits; skeleton_mapper_determinism.rs: skeleton_mapper_match_with_1_and_4_workers, skeleton_mapper_match_across_processes, a_changed_mapped_input_changes_the_digest (its mapped poses and its bodies); contact_tuning.rs: tuned_stacks_are_identical_with_1_and_4_workers; crates/oxijolt-sys/tests/determinism.rs: digest_is_identical_across_thread_counts
World state save and restore PhysicsWorld::save_state, save_state_of, restore_state, WorldState, StateError state.rs: rollback_replays_every_tick_bit_for_bit, a_state_restores_any_number_of_times, restore_undoes_saved_constraint_targets, restore_does_not_undo_unsaved_configuration, restore_after_a_structural_change_is_refused_and_changes_nothing, a_rejected_structural_call_keeps_a_state_restorable, a_failed_create_on_a_full_world_keeps_a_state_restorable, a_vehicle_in_zero_gravity_keeps_its_world_up_across_a_restore, a_state_of_another_world_is_refused, bodies_created_after_the_restore_point_get_the_original_ids, a_selected_bodies_state_replays_when_the_rest_is_static, bodies_left_out_of_a_state_keep_their_current_state, soft_bodies_replay_after_a_detour_restore, restore_does_not_undo_a_vertex_inverse_mass and the other tests in the file; constraint_forces_state.rs: readouts_restore_with_the_state_for_every_kind; state_leaks.rs: world_states_do_not_leak; crates/oxijolt-sys/tests/state_smoke.rs
Rollback helpers: reused state buffers, body selections, filtered restore, state size PhysicsWorld::save_state_into, restore_state_of, BodySelection, WorldState::new, WorldState::data_size, StateError::Body state_buffers.rs: a_state_saved_into_a_used_buffer_replays_like_save_state, a_buffer_belongs_to_the_world_that_saved_into_it_last, a_new_state_restores_into_no_world, a_refused_selection_leaves_the_buffer_as_it_was, a_ring_of_buffers_rolls_back_over_a_detour_bit_for_bit, a_movable_state_leaves_static_bodies_out, a_movable_state_holds_kinematic_and_inner_bodies, a_movable_state_replays_like_a_full_one, restoring_some_bodies_leaves_the_others_bit_for_bit, restoring_movable_bodies_keeps_static_bodies_where_they_are, a_selected_body_the_state_does_not_hold_keeps_its_state, inner_bodies_follow_their_characters, a_refused_filtered_restore_changes_nothing, a_filtered_restore_after_a_structural_change_is_refused, restoring_all_bodies_is_restore_state, a_filtered_restore_replays_identically_across_processes; state_filtered_parts.rs: a_filtered_restore_keeps_unselected_cloths_forces_and_wakes; state_buffer_allocations.rs: saving_into_a_used_buffer_allocates_nothing (every selection, selected saves after only full saves, worlds of two, one and two characters); state_sizes.rs: an_empty_world_holds_the_counts, a_static_body_adds_its_id_flag_and_pose, every_body_that_can_move_adds_the_same_bytes, a_resting_cube_adds_one_contact_pair_with_four_points, a_hinge_adds_its_index_and_solver_state, a_character_adds_its_inner_body_and_keeps_its_contacts_in_its_own_state; state_buffer_leaks.rs: state_buffers_and_filtered_restores_do_not_leak (Windows)
Debug wireframe as line data (debug-renderer) PhysicsWorld::debug_lines, debug_lines_into, DebugLines, DebugLineSettings debug_lines.rs: near_colliders_present_far_absent_terrain_present, same_calls_give_identical_lines, line_cap_gives_exactly_the_cap_and_truncated, hidden_groups_vanish, compound_child_pose_applies_child_rotation_before_body_rotation; debug_lines_leaks.rs; crates/oxijolt-sys/tests/debug_renderer_bindings.rs
Leak gate for per-call joltc objects (Windows; bounded memory growth, catches only leaks above its threshold) queries, rebase leaks.rs: per_call_joltc_objects_do_not_leak
Character settings with Jolt's defaults, validation PhysicsWorld::create_character, CharacterSettings, CharacterError, CharacterRef::penetration_recovery_speed, CharacterMut::set_penetration_recovery_speed character.rs: invalid_settings_and_poses_are_rejected_without_side_effects; src/character/tests.rs: default_settings_match_jolt; character_recovery.rs: penetration_recovery_speed_set_at_runtime_decides_the_push
Humanoid preset: a capsule of a height and radius standing on the position, owned by the settings and shared by their clones CharacterSettings::humanoid src/character/tests.rs: humanoid_puts_the_capsule_bottom_at_the_position, humanoid_refuses_bad_dimensions; presets.rs: a_humanoid_stands_on_a_floor_and_walks, humanoid_settings_outlive_their_clones, humanoid_settings_cross_threads (Send + Sync, a clone used and dropped on another thread), a_humanoid_accepts_a_borrowed_inner_body; character_leaks.rs (Windows): characters_do_not_leak
Character ids per world, removal CharacterId, character_ids, character_count, contains_character, remove_character character.rs: ids_count_from_one_are_never_reused_and_belong_to_their_world, removing_a_character_mid_run_leaves_the_others_sound
Character update: move by velocity, ground state and normal update_character, CharacterMut::set_linear_velocity, CharacterRef::ground_state, ground_normal, ground_body, GroundState character.rs: a_character_lands_on_a_floor_and_reports_it, linear_velocity_round_trips_and_moves_a_free_character, a_slope_limit_near_zero_turns_the_limit_off; src/character/tests.rs: ground_states_convert_and_report_support
Stick to floor and walk stairs ExtendedUpdateSettings character.rs: walk_stairs_climbs_a_step_that_stops_a_character_without_it; walker.rs: walking_down_a_30_degree_slope_has_no_hops (stick to floor as the floor snap)
Character study: which character laws the built-ins carry, per configuration (character-study.md) ExtendedUpdateSettings, CharacterSettings, CharacterMut::set_penetration_recovery_speed, refresh_character_contacts, the queries character_study.rs: law_1_slope_limit, law_2_stays_on_the_floor, law_3_steps_sharp, law_3_steps_rounded, law_4_no_hops_downhill, law_5v_push_out_is_not_velocity, law_5r_push_out_recovers, law_6_seams_are_one_surface, radial_acceptance, the_controls_are_seen, the_study_table_in_the_docs_matches_the_tests
Character study instruments the study harness (tests/study/) character_study.rs: decoded_heightfields_match_their_profiles, decoded_face_angles_match_the_scene, a_resting_character_has_zero_gap, seam_pair_matches_the_continuous_field, frames_round_trip, the_walker_row_reproduces_the_reference_near_step_bit_for_bit, tick_reports_account_for_every_displacement, law_predicates_reject_corrupted_traces
Character study determinism: repeated, across processes with 1 and 4 workers, restored after a detour, in a tilted frame the study caller character_study_determinism.rs: a_study_run_is_bit_exact_when_repeated, study_runs_match_across_processes_and_worker_counts, a_restored_study_run_continues_bit_for_bit_after_a_detour, the_study_rows_give_the_same_cells_in_a_tilted_frame, tilt_accounting_counts_flipped_and_divergent_cases
Character study rule 7: steep terrain slides, a steep structure holds, the terrain veto stands after the autostep and the snap, a wall beside a high ledge does not hold the character, the structure-edge snap takes a ledge edge and not a wall the study caller character_study_rules.rs: the_terrain_veto_stands_after_the_autostep_and_the_snap, a_steep_structure_holds_the_character_and_steep_terrain_does_not, walking_off_a_high_ledge_beside_a_wall_falls_to_the_floor, the_structure_edge_snap_takes_a_ledge_edge_and_not_a_wall_leaning_back (variants: high_ledge_beside_wall_survey)
Up and rotation per update (radial up) CharacterMut::set_up, set_rotation, set_position character.rs: up_and_rotation_set_per_update_give_the_same_walk_in_another_frame; walker.rs: a_rotated_floor_far_from_the_anchor_keeps_the_path, a_chunk_seam_is_crossed
Character contacts: body, layer, compound child group, contact normal; filters CharacterRef::active_contacts, CharacterContact, contact_compound_child, contact_object_layer, QueryFilter character.rs: a_character_lands_on_a_floor_and_reports_it, compound_children_report_their_group_and_filters_select_them
Inner body CharacterSettings::inner_body, InnerBody, is_inner_body, BodyError::OwnedByCharacter character.rs: an_inner_body_is_a_body_of_the_world_owned_by_its_character, dropping_a_world_with_characters_releases_them
Collisions between characters CharacterSettings::collide_with_characters character.rs: characters_that_collide_with_characters_keep_apart, removing_a_character_mid_run_leaves_the_others_sound
Character save and restore, chained replay CharacterRef::save_state, CharacterMut::restore_state, CharacterState character.rs: a_chained_replay_of_one_character_is_bit_exact, a_chained_replay_of_colliding_characters_is_bit_exact, a_restored_state_saves_the_same_bytes, a_restored_state_moves_the_inner_body_with_the_character; crates/oxijolt-sys/tests/character_smoke.rs: character_lands_and_its_restored_state_continues_bit_for_bit
Characters across a rebase PhysicsWorld::rebase, refresh_character_contacts character.rs: a_character_crosses_a_rebase_with_the_world
The game's near step on a radial planet (reference controller in test support, tests/common/walker.rs) built on the rows above walker.rs: step_law_climbs_up_to_045_but_not_05, a_step_under_a_low_ceiling_is_not_taken, the_autostep_never_climbs_a_dynamic_body_in_the_filter, slope_law_climbs_30_degrees_and_slides_back_from_60, steep_slopes_always_bring_the_walker_down, a_buried_walker_is_put_back_on_the_terrain, an_overlapping_wall_pushes_the_walker_out, a_jump_reaches_the_ballistic_apex_and_lands, rising_into_a_ceiling_resets_vel_up, chained_near_step_replay_is_bit_exact and the other tests in the file
Leak gate for characters (Windows) create, update, save and restore, remove character_leaks.rs: characters_do_not_leak
Character contact material lifetime: a character keeps the materials of its cached contacts alive, also when an update reuses contacts with a body whose shape was replaced or removed update_character, refresh_character_contacts, PhysicsWorld::restore_state character_materials.rs: a_character_whose_contact_body_was_removed_keeps_updating, a_character_whose_contact_shape_was_replaced_keeps_updating, a_listener_panic_still_retains_the_new_contacts_materials; src/character/tests.rs: cached_contact_materials_are_owned_until_the_contacts_change, a_world_restore_releases_the_contact_materials, a_character_restore_keeps_the_old_materials_until_the_next_update, a_filter_panic_still_releases_the_materials_of_dropped_contacts, contacts_sharing_a_material_hold_one_reference, a_character_keeps_updating_after_a_character_it_touched_is_removed; character_materials_leaks.rs (Windows): character_contact_materials_do_not_leak; oxijolt-sys material_smoke.rs: add_ref_and_count_follow_jolt
Vehicle settings with Jolt's defaults, validation WheeledVehicleSettings, WheelSettings, SpringSettings, VehicleEngineSettings, VehicleTransmissionSettings, VehicleDifferentialSettings, VehicleAntiRollBar src/vehicle/settings.rs: wheel_defaults_are_jolts, controller_defaults_are_jolts, constraint_differential_and_anti_roll_bar_defaults_are_jolts, built_settings_reach_jolt, step_coefficients_of_wheels_must_be_finite, step_coefficients_of_the_drivetrain_must_be_finite and the other validation tests in the file; vehicle.rs: invalid_vehicles_create_nothing. Anti-roll bars and the pitch and roll limit are tested for their defaults and validation only, not for their effect
Car preset: four mirrored wheels, front steering and drive, rear hand brake, anti-roll bars WheeledVehicleSettings::car src/vehicle/settings/presets.rs: car_preset_equals_the_explicit_settings; presets.rs: a_car_preset_drives_brakes_steers_and_shifts, car_preset_values_are_validated
Vehicle creation, ids, removal PhysicsWorld::create_wheeled_vehicle, remove_vehicle, VehicleId, vehicle_ids, vehicle_count, contains_vehicle, vehicle_of_body, VehicleError, BodyError::UsedByVehicle vehicle.rs: invalid_vehicles_create_nothing, vehicle_ids_are_sequential_and_never_reused, chassis_cannot_be_removed_while_a_vehicle_uses_it, a_removed_vehicle_no_longer_drives, dropping_a_world_with_vehicles_is_clean
Wheel collision testers and contact readout VehicleCollisionTester (ray, sphere, cylinder), VehicleRef::wheels, WheelState, WheelContact, VehicleMut::set_collision_tester vehicle.rs: wheel_contacts_match_the_ground_geometry (every tester on a box floor and a heightfield, against the analytic plane), start_overlap_reports_a_hard_point_without_depth, start_overlap_depth_comes_from_collide_shape, collision_tester_can_be_replaced, wheels_pass_through_soft_bodies_to_the_ground
Wheel poses in world space, for drawing VehicleRef::wheel_world_transform wheel_transforms.rs: a_resting_car_wheel_sits_on_its_suspension, steering_turns_the_front_axles, rolling_turns_the_wheel_about_its_axle, tank_and_bike_wheels_follow_their_suspension, wheel_world_transform_refuses_indices_past_the_last_wheel, wheel_transforms_move_with_a_rebase, wheel_transforms_keep_a_far_fractional_chassis_position (a rotated rebase to 1e6 m with a fraction under f64 positions, an offset centre of mass)
Driver input, engine and gear readout DriverInput, VehicleMut::set_driver_input, VehicleRef::engine_rpm, current_gear vehicle.rs: driver_input_drives_steers_and_brakes, braking_at_the_smallest_step_stays_finite
Caller-applied gravity, sleep VehicleMut::set_gravity, VehicleRef::gravity, world_up vehicle.rs: gravity_override_replaces_world_gravity, gravity_is_bounded_by_max_acceleration, sleeping_chassis_gets_no_override_force, never_sleeping_chassis_stays_awake; collision_steps.rs: a_vehicle_gravity_override_acts_like_world_gravity_in_every_collision_step
A car drives a route over heightfield terrain built on the rows above (route and controller in tests/common/vehicle.rs) vehicle.rs: drive_a_route_over_terrain (four waypoints, never tipped past 60°, two wheels down on 95 % of the ticks), drive_a_route_twice_gives_identical_bits
Leak gate for vehicles (Windows) create, drive, read, replace the tester, remove vehicle_leaks.rs: vehicles_do_not_leak
Vehicle kinds and typed ids VehicleId<K>, AnyVehicleId, VehicleKind, VehicleType, WheeledVehicle, TrackedVehicle, Motorcycle, remove_vehicle(impl Into<AnyVehicleId>) tracked_vehicle.rs: tank_chassis_is_guarded; motorcycle.rs: motorcycle_chassis_is_guarded; vehicle.rs: vehicle_ids_are_sequential_and_never_reused; root_glob.rs: the_vehicle_kinds_are_named_at_the_root; the compile_fail examples of VehicleMut (a tank's input on a car, a car's input on a tank)
Tracked vehicles: settings with Jolt's defaults, validation PhysicsWorld::create_tracked_vehicle, TrackedVehicleSettings (default_engine, default_transmission), VehicleTrackSettings, TrackedWheelSettings src/vehicle/settings/tracked_tests.rs: tracked_wheel_defaults_are_jolts, track_defaults_are_jolts, tracked_controller_defaults_are_jolts, built_tracked_wheels_reach_jolt, tracked_settings_are_validated, tracked_wheels_share_the_wheel_rules, track_wheel_radii_stay_within_max_ratio_of_the_driven_wheel, tracked_drive_envelope_bounds_the_drivetrain; tracked_vehicle.rs: invalid_tracked_vehicles_create_nothing; drivetrain_bounds.rs: overflowing_tracked_drivetrains_are_refused, the_strongest_light_tracks_stay_finite, the_strongest_tracks_with_the_widest_radius_ratio_stay_finite, the_strongest_tracks_on_the_widest_curve_stay_finite, unequal_track_inertias_are_refused, the_widest_track_inertia_ratio_stays_finite_on_high_friction_ground, tracks_heavy_against_their_chassis_are_refused, tracks_heavy_against_a_narrow_hull_are_refused, the_heaviest_accepted_tracks_stay_finite_on_high_friction_ground, jolt_tank_tracks_are_inside_the_track_mass_ratio
Tracked vehicles: driving and readout TrackedDriverInput, VehicleMut::<TrackedVehicle>::set_driver_input, VehicleRef::<TrackedVehicle>::tracks, track, track_wheels, driver_input, TrackState, TrackSide tracked_vehicle.rs: tank_pivots_in_place (drift below 5 cm, yaw rate above 2.3 rad/s), tank_climbs_a_12_degree_slope (more than 3 m of rise in 5 s), track_wheels_turn_with_their_track, brake_stops_the_tank, tracked_input_reads_back, tracked_inputs_are_validated, tank_testers, tank_wheels_pass_through_soft_bodies, rebase_rotates_a_tanks_gravity_override_and_tester_up
Motorcycles: settings with Jolt's defaults, validation PhysicsWorld::create_motorcycle, MotorcycleSettings, VehicleError::LeanSpringIntegrationNotSaved src/vehicle/settings/motorcycle_tests.rs: motorcycle_defaults_are_jolts, built_lean_settings_reach_jolt, motorcycle_settings_are_validated, max_lean_angle_is_80_degrees, lean_spring_rule_boundary; motorcycle.rs: motorcycle_settings_are_refused
Motorcycle preset: Jolt's MotorcycleTest sample MotorcycleSettings::bike presets.rs: bike_preset_equals_the_motorcycle_sample, a_bike_preset_rides_upright, bike_preset_values_are_validated
Motorcycles: riding, lean and readout VehicleMut::<Motorcycle>::set_driver_input, VehicleRef::<Motorcycle>::lean, MotorcycleLean, is_lean_controller_enabled, is_lean_steering_limit_enabled, driver_input motorcycle.rs: motorcycle_stays_upright_at_speed, motorcycle_leans_into_a_turn, without_the_lean_controller_it_falls_over, no_lean_torque_unless_both_wheels_touch, zero_gravity_steering_limit_applies_only_while_moving, lean_spring_at_its_bound_steps_finitely, rebase_rotates_the_target_lean, motorcycle_testers, motorcycle_wheels_pass_through_soft_bodies
Tracked vehicles and motorcycles: same results with 1 and 4 workers, rollback, leaks 12 tanks, 12 motorcycles and a car, 25 step listeners in 2 or 3 jobs; saves before contact, in a turn and in a gear shift vehicle_kinds_determinism.rs: vehicle_kinds_match_with_1_and_4_workers, vehicle_kinds_match_across_processes, vehicle_kinds_detect_a_changed_input, the_scene_moves_every_kind; vehicle_kinds_state.rs: vehicle_kinds_replay_after_a_detour, vehicle_kinds_replay_across_processes, tracked_input_tracks_and_target_lean_are_restored, motorcycle_replays_at_the_default_integration_coefficient, a_refused_tank_or_motorcycle_keeps_a_state_restorable, motorcycle_world_up_in_zero_gravity_is_not_restored; vehicle_kinds_leaks.rs: tracked_vehicles_and_motorcycles_do_not_leak (Windows)
Live engine and transmission, every vehicle kind; gear counts and clutch release time fixed at creation VehicleRef::engine_settings, transmission_settings, VehicleMut::set_engine, set_transmission, VehicleError::FixedAtCreation, extension JPH_WheeledVehicleController_SetEngine, _SetTransmission, JPH_TrackedVehicleController_SetEngine, _SetTransmission vehicle_tuning.rs: drivetrain_reads_back_as_set, more_engine_torque_accelerates_harder, a_longer_gear_ratio_changes_the_drive, gear_counts_and_clutch_release_time_are_fixed_at_creation, clutch_release_time_refusal_during_a_countdown, restore_keeps_live_drivetrain_settings, lower_rpm_limits_clamp_a_restored_rpm, invalid_live_drivetrains_change_nothing, drivetrain_setters_use_the_current_collision_tester; tracked_vehicle.rs: live_tank_engine_changes_after_fast_driving_step_finitely; src/vehicle/settings/live.rs: live_changes_keep_the_running_track_speed_bound; src/error/tests.rs: fixed_at_creation_names_the_setting; oxijolt-sys vehicle_tuning_smoke.rs: live_engine_reaches_wheeled_and_tracked_controllers, live_transmission_keeps_gear_and_refuses_fixed_changes
Live differentials of wheeled vehicles and motorcycles VehicleRef::differentials, differential_limited_slip_ratio, VehicleMut::set_differentials, WheeledControllerKind, extension JPH_WheeledVehicleController_SetDifferentials, _SetDifferentialLimitedSlipRatio vehicle_tuning.rs: moving_drive_to_the_rear_differential_changes_which_wheels_spin, limited_slip_ratio_changes_torque_split, a_motorcycle_differential_change_changes_its_drive, invalid_live_differentials_change_nothing; oxijolt-sys vehicle_tuning_smoke.rs: live_differentials_change_which_wheels_are_driven
Live tracks of tracked vehicles; track wheels fixed at creation VehicleRef::<TrackedVehicle>::track_settings, VehicleMut::<TrackedVehicle>::set_tracks, extension JPH_TrackedVehicleController_SetTrack tracked_tuning.rs: track_settings_read_back_as_set, heavier_brakes_stop_the_tank_sooner, a_higher_track_differential_ratio_changes_track_speed, more_track_damping_slows_the_tracks, track_wheels_are_fixed_at_creation, track_inertia_bounded_by_the_chassis, live_tracks_after_fast_driving_step_finitely; oxijolt-sys vehicle_tuning_smoke.rs: live_track_settings_reach_the_track_and_refuse_other_wheels
Tire max impulse callback of wheeled vehicles and motorcycles: friction coefficients per wheel, panics resumed by step, dropped with the vehicle VehicleMut::set_tire_max_impulse_callback, clear_tire_max_impulse_callback, VehicleRef::has_tire_max_impulse_callback, TireMaxImpulseInput, TireFriction, extension JPH_WheeledVehicleController_ResetTireMaxImpulseCallback tire_callback.rs: zero_friction_gives_no_drive, less_longitudinal_friction_spins_the_driven_wheels, default_friction_matches_no_callback, reduced_lateral_grip_widens_the_turn, outputs_are_clamped_to_the_friction_bounds, the_largest_friction_stays_finite, the_largest_friction_of_a_callback_matches_the_largest_friction_curves, the_callback_sees_contacting_wheels, clear_restores_jolts_default, a_panicking_callback_panics_out_of_step_and_the_world_stays_usable, after_a_panic_the_step_uses_jolts_default, callbacks_are_dropped_with_replace_clear_remove_and_world_drop, distinct_callbacks_per_vehicle, callback_survives_restore_and_rebase; src/panic_slot.rs: a_later_payload_whose_drop_panics_is_dropped_without_unwinding, take_empties_the_slot; oxijolt-sys vehicle_tuning_smoke.rs: tire_callback_reset_stops_calling_the_old_callback; the doctest of set_tire_max_impulse_callback
Vehicle tuning: same results with 1 and 4 workers, rollback, leaks 8 cars and 8 motorcycles with a slip-dependent tire callback and 8 tanks, every live setter of each kind at tick 30; the vehicle kinds' rollback scene changes every kind's drivetrain right after the save vehicle_tuning_determinism.rs: tuning_matches_with_1_and_4_workers, tuning_matches_across_processes, tuning_detects_a_changed_input, the_tuning_scene_moves_and_calls_back; vehicle_kinds_state.rs: vehicle_kinds_replay_after_a_detour, vehicle_kinds_replay_across_processes; vehicle_leaks.rs: vehicles_do_not_leak; vehicle_kinds_leaks.rs: tracked_vehicles_and_motorcycles_do_not_leak (Windows)
Constraint settings with Jolt's defaults, validation (ragdoll joints and world constraints) SwingTwistConstraintSettings, HingeConstraintSettings, SixDofConstraintSettings, MotorSettings, SpringSettings, SwingType, ConstraintSpace src/constraint/tests.rs: constraint_base_is_jolts_default, swing_twist_defaults_are_jolts, hinge_defaults_are_jolts, six_dof_defaults_are_jolts, fixed_and_free_map_to_jolts_sentinels, frames_are_validated, swing_twist_limits_are_validated, hinge_limits_are_validated, six_dof_limits_are_validated, motors_and_springs_are_validated; crates/oxijolt-sys/tests/constraint_smoke.rs: new_settings_init_to_jolts_defaults
World constraints of twelve kinds PhysicsWorld::create_constraint with FixedConstraintSettings, PointConstraintSettings, DistanceConstraintSettings, HingeConstraintSettings, SliderConstraintSettings, ConeConstraintSettings, SwingTwistConstraintSettings, SixDofConstraintSettings, GearConstraintSettings, RackAndPinionConstraintSettings, PulleyConstraintSettings, PathConstraintSettings constraints.rs: fixed_constraint_holds_a_box_under_a_static_bar, point_constraint_keeps_the_pendulum_pivot, distance_constraint_keeps_a_rod_length, hinge_limit_holds_a_falling_door, slider_limit_holds, cone_holds_a_hanging_body_within_its_angle, swing_twist_twist_limit_holds, six_dof_translation_limit_holds, six_dof_pyramid_holds_asymmetric_limits, gear_turns_the_second_hinge_at_the_ratio, rack_moves_at_the_pinion_rate, pulley_lifts_one_body_as_the_other_falls, pulley_with_ratio_two_moves_half_as_far, path_keeps_a_body_on_its_curve; crates/oxijolt-sys/tests/constraint_smoke.rs
Constraint motors, springs, targets and readout ConstraintRef, ConstraintMut, MotorState constraints.rs: hinge_velocity_motor_reaches_its_target_speed, hinge_position_motor_reaches_its_target_angle, soft_distance_spring_oscillates_and_damps, slider_position_motor_reaches_its_target, slider_soft_limit_spring_oscillates_and_damps, swing_twist_motor_reaches_target_orientation_with_a_rotated_parent, swing_twist_reads_back_its_motor_settings, six_dof_translation_spring_oscillates_and_damps, six_dof_rotation_position_motor_reaches_its_target, path_motor_drives_to_a_target_fraction, path_reads_back_its_motor_looping_and_rotation_impulses, looping_path_wraps, hinge_setters_check_their_values, changed_limits_motors_and_friction_act_on_sleeping_bodies
Constraint impulse readout and breaking ConstraintRef::total_lambda* of every kind, ConstraintMut::set_enabled constraint_forces.rs: a_weld_reads_the_weight_it_holds, a_weld_off_the_centre_reads_the_torque_it_holds, a_weld_reads_a_couple_in_its_rotation_part, the_readout_is_the_impulse_of_the_whole_step, point_cone_swing_twist_and_six_dof_read_the_hanging_weight, distance_and_pulley_read_the_rope_tension, hinge_and_slider_read_their_new_parts, motors_and_limits_read_the_load_they_hold, swing_twist_limits_and_motors_read_the_couple_they_hold, two_limited_swing_axes_read_one_limit_in_the_swing_y_part, world_vectors_follow_the_world_and_axis_parts_the_frame, a_soft_limit_spring_makes_six_dof_translation_per_axis, six_dof_reads_per_axis_parts_and_motors, couplings_read_the_load_they_carry, path_reads_its_parts, a_disabled_constraint_keeps_its_last_readout, a_sleeping_constraint_keeps_its_last_readout, a_weld_reads_the_weight_of_its_last_collision_step; constraint_forces_state.rs: readouts_restore_with_the_state_for_every_kind, a_disabled_bond_saved_stays_disabled; state.rs: restore_after_a_structural_change_is_refused_and_changes_nothing (removing a constraint); constraint_forces_determinism.rs: constraint_impulses_are_identical_with_1_and_4_workers; the breakable weld in constraints.md (doctest)
Constraint ids, guards and removal ConstraintId, AnyConstraintId, remove_constraint, constraint_ids, contains_constraint, constraints_of_body, ConstraintError, BodyError::UsedByConstraint constraints.rs: constraint_ids_are_typed_ordered_and_never_reused, wrong_world_and_removed_ids_are_rejected, bodies_of_constraints_cannot_be_removed, constraints_refuse_ragdoll_parts_inner_bodies_and_one_body, gears_racks_and_pulleys_need_two_dynamic_bodies, invalid_constraint_creates_nothing, removing_a_constraint_wakes_its_bodies, a_new_constraint_wakes_its_sleeping_bodies, every_setter_wakes_the_constraint_bodies, dropping_a_world_with_constraints_is_clean
Gears and racks that reference hinges and sliders GearConstraintSettings::hinges, RackAndPinionConstraintSettings::constraints, ConstraintError::UsedByConstraint constraints.rs: gear_references_correct_drift, rack_references_correct_drift, a_referenced_hinge_cannot_be_removed, unrelated_or_reversed_references_are_rejected, gear_keeps_its_velocity_relation_at_the_largest_ratio
Hermite paths HermitePath, HermitePathPoint, PathRotationConstraint constraints.rs: invalid_paths_are_rejected, path_validation_accepts_its_boundary, looping_path_wraps
Leak gate for constraints (Windows) create, step, read, remove constraint_leaks.rs: constraints_do_not_leak
Skeleton, ragdoll settings, stabilized masses Skeleton, SkeletonJoint, RagdollSettings::new, new_stabilized, RagdollPart, RagdollJoint src/ragdoll/settings.rs: skeletons_are_validated, ragdoll_settings_are_validated, heightfield_parts_are_rejected, stabilized_settings_build; ragdoll.rs: plain_settings_keep_the_masses_and_stabilized_ones_the_total, one_settings_value_serves_two_worlds
Ragdoll creation, ids, removal PhysicsWorld::create_ragdoll, remove_ragdoll, RagdollId, ragdoll_ids, ragdoll_count, contains_ragdoll, ragdoll_of_body, RagdollError, BodyError::OwnedByRagdoll ragdoll.rs: ragdoll_parts_and_ids_are_guarded (including a world too small for the parts), removing_a_ragdoll_drops_what_rests_on_it, dropping_a_world_with_ragdolls_is_clean; src/ragdoll/mod.rs: a_created_chain_reports_its_parts_and_joints
No collisions between a ragdoll's own parts RagdollSettings ragdoll.rs: two_ragdolls_collide_with_each_other_but_not_with_themselves, the_same_parts_as_plain_bodies_collide (the control), humanoid_settles_on_a_heightfield_in_a_second_world (every part pair on every tick while the ragdoll is awake)
Pose readout and writing, kinematic drive RagdollRef::pose, root_transform, RagdollMut::set_pose, drive_to_pose_using_kinematics, set_motion_type, SkeletonPose ragdoll.rs: poses_read_back_in_world_transforms, kinematic_parts_reach_the_driven_pose; src/ragdoll/settings.rs: poses_are_validated
Motor drive and joint readings RagdollMut::drive_to_pose_using_motors, stop_motors, RagdollRef::joint, joint_motors_on, JointReading ragdoll.rs: motors_drive_each_joint_kind_to_its_target (a hinge elbow and knee, a six-DOF hip and a swing-twist neck, driven from the bind pose), motors_drive_joints_of_a_turned_ragdoll_in_the_parent_frame, rebase_moves_a_settled_ragdoll_rigidly (joint readings before and after a rebase), humanoid_settles_on_a_heightfield_in_a_second_world (the limit check reads every joint)
Settle detection SettleDetector, RagdollRef::is_calm src/ragdoll/settle.rs: calm_updates_in_a_row_settle, default_is_the_rest_rule, invalid_limits_are_rejected; ragdoll.rs: humanoid_settles_on_a_heightfield_in_a_second_world
A 12-capsule humanoid settles on a heightfield in a second world (fixture in tests/common/ragdoll.rs) built on the rows above ragdoll.rs: humanoid_settles_on_a_heightfield_in_a_second_world (caller-applied gravity, the main world stepping on another thread, settled within 600 ticks (measured: tick 141), joints within 0.01 rad of their limits at rest), humanoid_joints_overshoot_their_limits_only_boundedly_during_the_drop (below 0.40 rad on every tick of that drop), an_environment_ray_passes_through_a_resting_part
Leak gate for ragdolls (Windows) settings, create, drive, read, remove ragdoll_leaks.rs: ragdolls_do_not_leak
Skeleton mapper between a ragdoll and an animation skeleton (fixture in tests/common/animation.rs) SkeletonMapper, MappedSkeleton, TranslationLocks, RagdollError::UnmappedJoint, HierarchyMismatch, DegenerateChain skeleton_mapper.rs: neutral_poses_map_onto_each_other, direct_joints_follow_the_ragdoll, a_chain_start_turns_toward_the_next_ragdoll_joint, the_longest_chain_wins_and_ties_go_to_the_first_joint, unmapped_joints_follow_their_parents, reverse_mapping_uses_direct_joints_only, all_translation_locks_keep_neutral_offsets, selected_translation_locks, neutral_root_offsets_are_compared_in_one_frame, the_mapper_owns_its_state, mapped_poses_drive_a_ragdoll (pose, motors from a turned start, kinematic drive), mapping_is_a_pure_function (three threads); src/ragdoll/mapper/tests.rs: a_mapper_matches_joints_by_name, lock_masks_flag_each_listed_joint, a_long_twisting_chain_maps (128 links turning 45° each), a_mapper_is_send_and_sync
Leak gate for skeleton mappers (Windows) build with each kind of lock, map both ways, refusals skeleton_mapper_leaks.rs: skeleton_mappers_do_not_leak
Soft bodies: shared settings, creation, vertex readout and writes SoftBodySharedSettings, SoftBodySharedSettingsBuilder, SoftBodySettings, PhysicsWorld::create_soft_body, soft_body, soft_body_mut, SoftBodyRef, SoftBodyMut soft_body.rs: a_cloth_pinned_at_two_corners_drapes_over_a_sphere, vertices_read_back_in_world_space, pinning_and_unpinning_vertices, invalid_vertex_writes_change_nothing, a_kinematic_vertex_moves_to_its_target_and_keeps_its_velocity, a_pressurised_ball_keeps_its_size_on_the_floor, a_tetrahedral_cube_keeps_its_volume_on_the_floor, explicit_constraints_add_to_the_generated_ones, explicit_edges_without_faces_hold_a_pendulum, queries_find_a_cloth, one_shared_settings_serves_worlds_on_two_threads and the other tests in the file; src/soft_body/tests.rs: default_settings_match_jolt, default_vertex_attributes_match_jolt, invalid_vertices_are_rejected, invalid_faces_are_rejected; crates/oxijolt-sys/tests/soft_body_smoke.rs
Body APIs a soft body refuses BodyError::NotRigidBody, BodyMut::add_force on a soft body soft_body.rs: body_level_velocity_torque_and_point_force_refuse_soft_bodies, constraints_and_vehicles_refuse_soft_bodies, add_force_on_a_rotated_soft_body_pushes_along_the_world_force
Leak gate for soft bodies (Windows) shared settings, create, step, read, write, remove soft_body_leaks.rs: soft_bodies_do_not_leak
Contact, activation and soft body contact events EventSettings, PhysicsWorld::set_event_settings, take_events, WorldEvents, ContactEvent, ActivationEvent, SoftBodyContacts, SoftBodyValidation listeners.rs: a_default_world_reports_nothing, contacts_are_added_persisted_and_removed_with_their_sub_shapes, persisted_contacts_are_opt_in, removing_a_body_reports_its_contact_removed_with_the_stale_id, falling_asleep_removes_contacts_and_deactivates, activation_follows_creation_wake_sleep_and_removal_but_not_restore, several_steps_queue_in_step_order, worlds_stepped_on_two_threads_see_only_their_own_events, a_cloth_on_a_table_reports_its_vertex_contacts, rotated_cloth_contacts_are_converted_to_world_space, a_replay_after_a_detour_reports_the_same_events and the other tests in the file; src/listener/tests.rs: a_panic_in_any_callback_during_a_step_is_resumed_by_step, a_panic_outside_a_step_is_resumed_by_take_events; crates/oxijolt-sys/tests/listener_smoke.rs
Contact listener ContactListener, PhysicsWorld::set_contact_listener, ContactSettings, SoftBodyContactSettings, ContactSettingsRejection, StepReport::rejected_contact_settings contact_listener.rs: a_listener_makes_ice_slippery, a_conveyor_moves_a_resting_cube, sensor_contacts_let_a_cube_fall_through_and_are_still_reported, rejected_soft_body_contacts_let_a_cloth_fall_through, a_panicking_listener_is_resumed_by_step, continuous_collision_with_a_listener_steps_cleanly; src/listener/tests.rs: settings_are_checked_again_against_the_contact_that_takes_them, a_rejection_is_recorded_and_the_listener_is_still_called, settings_moved_to_a_contact_they_do_not_fit_are_rejected
Contact validation ContactListener::contact_validate, ContactCandidate, ValidateResult contact_validation.rs: rejecting_a_pair_lets_a_body_fall_through_the_floor, a_one_way_platform_lets_a_body_through_from_below_and_holds_it_from_above, own_projectiles_pass_through_their_shooter, validation_sees_body1_with_the_higher_motion_type, continuous_collision_is_validated_too, soft_bodies_use_their_own_validator, independent_worlds_with_different_validators_step_concurrently; src/listener/tests.rs: a_validate_panic_accepts_and_is_resumed_by_step, without_a_user_listener_validation_accepts_every_pair; crates/oxijolt-sys/tests/contact_listener2_smoke.rs (the extension's listener: no faces, every validate result, settings field by field, removals, a null validate proc)
Contact-cache invalidation as part of the state BodyMut::invalidate_contact_cache, WorldState, BodyMut::set_shape contact_cache.rs: a_cached_accepted_pair_is_not_validated_until_invalidated, a_cached_rejected_pair_stays_rejected_until_invalidated, an_invalidation_saved_before_the_step_is_replayed, an_invalidation_before_a_restore_does_not_reach_the_replay, a_detour_invalidation_is_dropped_by_restoring_a_clean_state, repeated_invalidations_are_one_request, invalidating_a_sleeping_body_wakes_it_and_revalidates_its_pairs, an_idle_step_keeps_the_request_pending, a_partial_state_saves_and_restores_the_requests, a_removed_body_leaves_no_request, a_state_saved_right_after_set_shape_replays_with_the_new_shape
Character contact listener CharacterContactListener, PhysicsWorld::set_character_contact_listener, BodyVelocity, CharacterContactSettings, CharacterContactKey character_listener.rs: a_conveyor_moves_a_character_standing_on_a_static_body, adjust_receives_the_bodys_user_data, a_rejected_body_contact_lets_the_character_walk_through, a_rejected_character_contact_lets_two_characters_pass, a_character_without_impulses_does_not_push_a_box_sideways, a_moving_wall_that_cannot_push_does_not_push_the_character, a_moving_character_that_cannot_push_does_not_push_the_character, added_persisted_removed_follow_a_walk_across_two_boxes, removals_arrive_sorted_after_the_contact_map_grew, a_panic_in_contact_removed_keeps_the_delivered_prefix, removing_a_contacted_body_or_character_reports_its_removal, refresh_reports_added_for_a_character_created_on_the_ground, one_extended_update_is_one_tracking_scope, callbacks_run_on_the_calling_thread, replacing_or_removing_the_listener_takes_effect_at_the_next_update, independent_worlds_with_different_character_listeners_update_concurrently; src/character/tests.rs: removals_sort_by_body_character_and_sub_shape, a_panic_in_any_listener_callback_is_resumed_by_the_update, a_change_followed_by_a_panic_keeps_the_jolt_values, a_listener_is_not_called_after_a_filter_panicked, simultaneous_filter_and_listener_failures_keep_one_payload
Collision groups GroupFilterTableBuilder, GroupFilterTable, CollisionGroup, BodySettings::collision_group, SoftBodySettings::collision_group, CollisionGroupError collision_groups.rs: bodies_of_one_sub_group_pass_through_each_other, a_disabled_pair_passes_and_an_enabled_pair_collides, different_group_ids_always_collide, same_group_id_with_different_tables_never_collides, grouped_bodies_collide_with_ungrouped_ones, can_collide_matches_the_simulation, a_chain_without_self_collision, a_vehicle_ignores_its_driver_body, a_solver_excluded_body_is_still_found_by_queries_and_blocks_characters, a_sensor_does_not_see_a_body_its_group_excludes, a_cloth_ignores_a_body_of_its_sub_group, ragdoll_parts_refuse_a_collision_group, caller_groups_never_alias_a_ragdoll, two_ragdolls_from_one_settings_collide_with_each_other, a_grouped_ragdoll_replays_after_a_restore, tables_outlive_their_handles, builder_and_group_boundaries, enabling_a_disabled_pair_makes_it_collide_again; group_table_first_call.rs: a_table_built_before_any_world_works; src/ragdoll/mod.rs: ragdoll_group_ids_stop_below_the_invalid_group
Contact control: determinism and rollback the three rows above contact_control_determinism.rs: contact_control_is_identical_with_1_and_4_workers, contact_control_is_identical_with_caller_job_systems, contact_control_replays_after_a_detour_in_one_process, contact_control_replays_after_a_detour_across_processes, the_scenes_exercise_their_rules
Leak gate for contact control (Windows) validating listeners, group tables and grouped bodies, the per-update character listener, invalidations, a world per round contact_control_leaks.rs: contact_control_does_not_leak (events.md)
Leak gate for listeners, materials and worlds (Windows) listener replacement, material shapes, a world per round listener_leaks.rs: listeners_materials_and_worlds_do_not_leak (events.md describes the gate)
Leak gate for the new shapes (Windows) every new constructor, the refusals, a failed Jolt creation, bodies of a hull and a mesh mesh_shapes_leaks.rs: new_shapes_do_not_leak
Magnitude policy oxijolt::limits limits.rs and the unit tests in src/limits/tests.rs; the table below names the test of each input
Jolt assertion handler (asserts feature) installed once per process before JPH_Init assertions.rs: a_failed_jolt_assertion_aborts_with_its_message; src/jolt_assert.rs: only_the_pinned_update_error_continues
Raw bindings oxijolt-sys crates/oxijolt-sys/tests/smoke_test.rs: box_falls_onto_static_box, callback_job_system_steps_a_world, single_threaded_job_system_steps_a_world, single_threaded_job_system_runs_several_collision_steps (extension JPH_JobSystemSingleThreaded_Create); character_smoke.rs: character_lands_and_its_restored_state_continues_bit_for_bit, copying_no_bytes_accepts_a_null_buffer; vehicle_smoke.rs: vehicle_constraint_steps_and_tears_down, vehicle_step_listener_applies_the_gravity_override_once_per_collision_step (extension JPH_VehicleStepListener_*), motorcycle_target_lean_is_checked_read_and_written; vehicle_tuning_smoke.rs: the live drivetrain setters and the tire callback reset of the extension (see the vehicle rows above); ragdoll_smoke.rs: ragdoll_parts_and_constraints_reach_jolt; constraint_smoke.rs, state_smoke.rs, soft_body_smoke.rs, listener_smoke.rs, material_smoke.rs; skeleton_mapper_smoke.rs: the aligned JPH_SkeletonMapper_*2 functions through misaligned arrays, Jolt's mapping stages (identity for unmatched ragdoll joints in reverse, outputs over their inputs in both directions) and every refusal; layout checks at compile time in crates/oxijolt-sys/src/layout.rs
Committed bindings and the supported targets oxijolt-sys, cargo xtask bindings xtask/src/main.rs: every_registered_target_is_accepted, narrow_and_unregistered_targets_are_refused, bindings_files_are_distinct, every_selectable_bindings_file_is_committed and the other tests in the file; CI's Committed bindings job compares them with LLVM 18 output
Examples in the guides and the README guide.md and the other guides in docs/, README.md doctests of the #[cfg(all(doctest, repository_docs))] items at the end of crates/oxijolt/src/lib.rs (cargo test -p oxijolt --doc; the repository only); the hello_world example, which CI runs
Plane shapes Shape::new_plane, new_plane_with_material plane_shape.rs: only_static_bodies_take_a_plane, planes_are_refused_where_shapes_must_move_or_query, a_static_body_may_change_to_a_plane, bodies_rest_on_a_plane, a_box_slides_down_a_tilted_plane, a_box_outside_the_half_extent_falls_past, a_compound_with_a_plane_child_catches_a_body, cloth_lands_on_a_plane, a_character_stands_and_walks_on_a_plane, rays_hit_a_plane_from_above_and_start_inside_it_from_below, contacts_report_the_planes_material; debug_lines.rs: a_plane_is_drawn_as_two_triangles; helpers_leaks.rs
Point queries PhysicsWorld::collide_point, CollidePointHit, Shape::collide_point point_queries.rs: boxes_spheres_and_planes_have_exact_boundaries, rounded_and_hull_shapes_hold_within_a_tenth_of_a_millimetre, meshes_count_the_triangles_above_the_point, heightfields_contain_nothing, soft_bodies_are_tested_by_their_faces, compounds_report_every_child_that_holds_the_point, shape_points_are_in_the_shapes_own_frame, a_plane_child_is_bounded_by_its_half_extent, world_queries_apply_every_filter_part_and_sort_by_body, world_queries_read_from_many_threads, far_points_find_small_bodies; src/filter.rs: a_panic_in_a_filter_callback_resumes_after_the_query; helpers_determinism.rs
Collision estimates EventSettings::collision_estimates, CollisionEstimate, ContactEvent::Added::estimate collision_estimates.rs: estimates_match_one_step_of_an_isolated_pair, a_bouncing_box_is_estimated_to_leave_at_half_speed, under_gravity_the_estimated_bounce_is_faster_by_restitution_g_dt, a_contact_found_by_the_continuous_stage_is_estimated, estimates_are_off_by_default_and_follow_the_contacts_switch, estimating_does_not_change_the_simulation, sensor_contacts_have_no_estimate, estimates_use_the_settings_jolt_resolves_the_contact_with, a_rejected_transplant_is_estimated_with_jolts_settings, locked_axes_are_not_part_of_the_estimate; src/listener/tests.rs: a_panic_while_copying_an_estimate_frees_joltcs_impulses; src/listener/order.rs: estimates_separate_added_contacts; event_determinism.rs; helpers_determinism.rs; collision_estimate_leaks.rs

CI runs the whole test suite on Windows (MSVC) and Linux (GCC), each in five configurations: default, cross-platform-deterministic, double-precision, debug-renderer and asserts. The tests behind the debug-renderer feature run only in that configuration. The leak gates read the process's private bytes through a Windows API and are built only on Windows.

Not in the safe API yet (joltc exposes them, so oxijolt-sys has them):

  • for rigid bodies, setters after creation for the sensor flag, user data, gravity factor, friction, restitution, damping, object layer and motion quality (each needs a rollback rule, since Jolt does not save them); mCollideKinematicVsNonDynamic; and allowed-DOF sets without a translation axis;
  • the manual transmission, a motorcycle's lean integration decay and wheel base readout;
  • Jolt's rigid-body Character;
  • the character contact listener's solve callbacks (OnContactSolve, OnCharacterContactSolve), a collision group for a character's inner body, and collision group changes after creation (Jolt does not save groups).

Skinned soft bodies (Jolt's skin constraints) are in neither layer.

Inputs and their boundary tests

Every public setter and constructor that takes a magnitude, the rule it applies, and the tests that check it at its boundary.

Input Rule Boundary test
WorldSettings::gravity, PhysicsWorld::set_gravity MAX_ACCELERATION world_gravity_is_bounded_by_max_acceleration
WorldSettings::max_contact_constraints 1..=WorldSettings::MAX_CONTACT_CONSTRAINTS contact_constraint_capacity_is_bounded
WorldSettings::max_bodies, worker_threads Jolt's and oxijolt's counts invalid_settings_are_rejected, worker_thread_bounds_are_validated
WorldSettings::job_system (JobSystem::max_concurrency) 1..=WorldSettings::MAX_CONCURRENCY, read once in PhysicsWorld::new max_concurrency_is_bounded
WorldSettings::velocity_steps, position_steps MIN_VELOCITY_STEPS..=MAX_SOLVER_STEPS, 0..=MAX_SOLVER_STEPS (limits) step_counts_outside_jolts_range_are_refused, step_counts_read_back_from_jolt
WorldSettings::penetration_slop, speculative_contact_distance 0..=MAX_SHAPE_EXTENT (limits) contact_distances_are_validated, contact_distances_at_their_bounds_keep_a_small_scene_finite, far_bodies_within_the_speculative_distance_stay_finite
WorldSettings::max_body_pairs, temp_allocator_size at least 1; Jolt asserts nothing on their size, and joltc's temp allocator falls back to malloc invalid_settings_are_rejected
PhysicsWorld::step delta time MIN_DELTA_TIME..=MAX_DELTA_TIME step_rejects_delta_time_above_the_bound, step_rejects_delta_time_below_the_bound
PhysicsWorld::step_with_collision_steps collision count 1..=MAX_COLLISION_STEPS (limits) collision_step_counts_outside_the_bound_are_refused, a_saturated_update_at_max_collision_steps_fits_jolts_job_pool
PhysicsWorld::step_with_collision_steps collision step length delta_time / collision_steps >= MIN_DELTA_TIME, and the total as for step collision_steps_shorter_than_min_delta_time_are_refused, bad_total_delta_times_are_refused_for_every_count
PhysicsWorld::rebase translation 2 * MAX_POSITION per axis; results finite rebase_translation_is_bounded_by_twice_the_frame
BodySettings::position MAX_POSITION body_settings_are_bounded
BodySettings::linear_velocity, angular_velocity MAX_LINEAR_VELOCITY, MAX_ANGULAR_VELOCITY body_settings_are_bounded, creation_velocities_agree_with_jolts_length_in_many_directions
BodySettings::restitution 0..=1 body_settings_are_bounded
BodySettings::gravity_factor MAX_GRAVITY_FACTOR body_settings_are_bounded
BodySettings::mass, PhysicsWorld::create_body computed mass MIN_MASS..=MAX_MASS for dynamic bodies body_settings_are_bounded, computed_dynamic_mass_is_bounded_and_kinematic_mass_is_not
BodySettings::mass_and_inertia mass within MIN_MASS..=MAX_MASS; inertia finite and symmetric; principal moments at least MIN_PROVIDED_INERTIA and at most 6 · mass · MAX_SHAPE_EXTENT² (Frobenius norm for a tensor that is not diagonal); a tensor that is not diagonal positive definite and well conditioned; refused by RagdollSettings::new_stabilized (see limits.md) body_settings.rs: invalid_provided_inertia_is_refused, provided_inertia_at_its_bounds_steps_finitely; ragdoll.rs: provided_inertia_on_a_ragdoll_part
PhysicsWorld::create_body computed inertia of a dynamic or kinematic body (also a character's inner body and a part of RagdollSettings::new, new_stabilized) an exactly diagonal tensor with invertible moments or near zero; otherwise smallest principal moment bounded from below at least MIN_INERTIA_RATIO (4.8e-4) of its Frobenius norm (see limits.md) rigid_body_inertia_floor_holds_at_its_boundary, rigid_body_inertia_at_its_bound_decomposes, inner_body_inertia_at_its_bound_decomposes, stabilized_ragdoll_inertia_at_its_bound_decomposes
BodySettings::friction 0..=MAX_FRICTION body_settings_are_bounded, friction_at_the_bound_keeps_contacts_finite
BodySettings::linear_damping, angular_damping finite, at least 0: Jolt scales by max(0, 1 - c·dt) (MotionProperties.inl:144-145) invalid_damping_is_rejected
BodySettings::rotation, BodyMut::set_rotation finite unit quaternion invalid_body_settings_are_rejected
BodyMut::set_position, set_position_and_rotation MAX_POSITION body_setters_are_bounded_and_rejection_changes_nothing
BodyMut::set_linear_velocity, set_angular_velocity MAX_LINEAR_VELOCITY, MAX_ANGULAR_VELOCITY body_setters_are_bounded_and_rejection_changes_nothing
BodyMut::add_force accumulated ` F
BodyMut::add_torque, add_force_at_point accumulated torque within MAX_ANGULAR_ACCELERATION, counting the rounding of Jolt's f32 cross product (see limits.md); point within MAX_POSITION; f32 torque products torques_are_bounded_by_the_angular_acceleration_they_give, point_forces_along_a_long_lever_count_jolt_rounding; src/body/tests.rs: point_torque_rejects_overflowing_products_even_when_they_cancel, point_torque_rounding_covers_every_f32_evaluation_order
BodyMut::add_impulse finite; on a dynamic body ` J
BodyMut::add_angular_impulse finite; on a dynamic body ` L
BodyMut::add_impulse_at_point both impulse rules with L = (p - com) × J, the angular one for the largest L Jolt's f32 cross product can give (see limits.md); point within MAX_POSITION; f32 cross product products body_controls.rs: point_impulses_are_bounded_by_the_angular_impulse_of_their_lever, angular_impulses_are_bounded_by_the_angular_velocity_change, point_impulses_along_a_long_lever_count_jolt_rounding; src/body/tests.rs: point_torque_rounding_covers_every_f32_evaluation_order
BodyMut::move_kinematic position within MAX_POSITION, unit rotation, step delta time; Jolt's implied velocities within MAX_LINEAR_VELOCITY and MAX_ANGULAR_VELOCITY body_controls.rs: kinematic_moves_are_bounded_by_the_velocities_they_imply
BuoyancySettings::surface position within MAX_POSITION; normal a finite unit vector buoyancy.rs: invalid_inputs_change_nothing
BuoyancySettings::buoyancy, linear_drag, angular_drag finite, not negative; then the product chains and squared lengths of limits.md invalid_inputs_change_nothing, bodies_at_the_bounds_stay_finite, small_light_and_far_buoyancy_centres_stay_finite; src/limits/buoyancy/tests.rs: each_chain_has_its_boundary, nan_in_any_input_is_refused, zero_factors_do_not_hide_large_ones, accepted_inputs_stay_finite_in_any_association, rotated_anisotropic_inertia_at_the_bound_stays_finite, drag_coefficients_at_their_bound_stay_finite, large_calm_bodies_are_accepted
BuoyancySettings::fluid_velocity MAX_LINEAR_VELOCITY invalid_inputs_change_nothing, bodies_at_the_bounds_stay_finite
BodyMut::apply_buoyancy_impulse gravity, delta time MAX_ACCELERATION; the bounds of PhysicsWorld::step invalid_inputs_change_nothing, bodies_at_the_bounds_stay_finite
BodyMut::apply_buoyancy_impulse buoyant velocity change b · Vs / V · abs(gf) · length(g) · dt <= MAX_VELOCITY_CHANGE, for both signs of the gravity factor (see limits.md) invalid_inputs_change_nothing, velocities_are_clamped_right_after_the_call; src/limits/buoyancy/tests.rs: both_signs_of_the_gravity_factor_are_bounded_alike
PhysicsWorld::activate_bodies_in_box corners within MAX_POSITION, min <= max per axis body_controls.rs: activation_box_is_validated, box_activation_compares_in_caller_precision
BodySettings::allowed_dofs a translation axis; all six on a static body that cannot move src/body/tests.rs: dofs_without_translation_are_refused; body_settings.rs: a_static_body_that_cannot_move_refuses_restricted_dofs
BodySettings::sensor discrete motion quality; no static-only shape sensors.rs: sensor_rules_refuse_static_only_shapes_and_linear_cast
BodySettings::allow_dynamic_or_kinematic zero initial velocities; the shape and inertia rules of a kinematic body body_structure.rs: a_movable_static_body_needs_zero_initial_velocities, allow_dynamic_or_kinematic_pays_the_moving_rules_at_creation
BodyMut::set_motion_type to dynamic mass within MIN_MASS..=MAX_MASS; no static-only shape body_structure.rs: light_kinematic_body_cannot_become_dynamic, kinematic_mesh_body_cannot_become_dynamic
BodyMut::set_shape mass within MIN_MASS..=MAX_MASS; the shape and inertia rules of create_body for the body's motion type, movement capability and sensor flag; no pending forces on a dynamic body shape_changes.rs: set_shape_applies_the_creation_rules_per_motion_type, set_shape_refuses_pending_forces
BodyMut::reset_forces none reset_forces_ignores_static_and_kinematic_bodies
CharacterSettings::mass 0..=MAX_MASS character_settings_and_setters_are_bounded
CharacterSettings::shape_offset MAX_SHAPE_EXTENT per axis character_settings_and_setters_are_bounded
CharacterSettings::humanoid height and radius radius finite and positive; height finite and more than twice the radius; the capsule within MAX_SHAPE_EXTENT humanoid_refuses_bad_dimensions
CharacterSettings::predictive_contact_distance, character_padding, collision_tolerance 0..=MAX_SHAPE_EXTENT (tolerance positive) character_settings_and_setters_are_bounded
CharacterSettings::max_strength and the other settings existing ranges; strength needs no bound (see limits.md) invalid_settings_and_poses_are_rejected_without_side_effects
PhysicsWorld::create_character position, CharacterMut::set_position MAX_POSITION character_settings_and_setters_are_bounded
CharacterMut::set_linear_velocity MAX_LINEAR_VELOCITY; Jolt does not clamp a character character_settings_and_setters_are_bounded
CharacterMut::set_penetration_recovery_speed 0..=1, finite character_settings_and_setters_are_bounded
CharacterMut::set_up, set_rotation unit vector, unit quaternion invalid_settings_and_poses_are_rejected_without_side_effects
PhysicsWorld::update_character gravity MAX_ACCELERATION character_update_gravity_and_steps_are_bounded
PhysicsWorld::update_character weight impulse character mass times gravity times delta time at most MAX_WEIGHT_IMPULSE character_weight_impulse_at_a_lever_arm_is_bounded, weight_impulse_check_accepts_its_bound_and_rejects_beyond
ExtendedUpdateSettings steps and forward distances MAX_SHAPE_EXTENT character_update_gravity_and_steps_are_bounded
CharacterMut::restore_state only states from save_state exist a_restored_state_saves_the_same_bytes
PhysicsWorld::restore_state, restore_state_of only states from save_state, save_state_of or save_state_into of the same world at the same epoch exist; restore_state_of restores a bodies-only stream it saved itself under the same mutable borrow tests/state.rs, tests/state_buffers.rs
VehicleMut::set_gravity MAX_ACCELERATION gravity_is_bounded_by_max_acceleration
WheelSettings::new position, suspension_force_point MAX_SHAPE_EXTENT per axis wheel_magnitudes_are_bounded_by_the_policy
WheelSettings suspension min, max and preload lengths, radius, width 0..=MAX_SHAPE_EXTENT (radius positive, max length at least min length) wheel_magnitudes_are_bounded_by_the_policy
WheeledVehicleSettings::car, MotorcycleSettings::bike wheel position and radius no rule of their own: the wheel rules above and the motorcycle's wheel base, checked by create_wheeled_vehicle and create_motorcycle car_preset_values_are_validated, bike_preset_values_are_validated
WheelSettings::suspension_spring Jolt's stiffness and damping at most MAX_SPRING_COEFFICIENT for a chassis of MAX_MASS suspension_springs_are_bounded_by_the_coefficient, vehicle_springs_and_anti_roll_bar_at_their_bounds_step_finitely
VehicleAntiRollBar::stiffness 0..=VehicleAntiRollBar::MAX_STIFFNESS anti_roll_bars_are_validated, vehicle_springs_and_anti_roll_bar_at_their_bounds_step_finitely
WheelSettings inertia, angular damping, brake torques; engine, transmission and differential settings finite, in their ranges, and every step coefficient they form finite at both time-step extremes; not bounded one by one wheel_values_are_validated, step_coefficients_of_wheels_must_be_finite, step_coefficients_of_the_drivetrain_must_be_finite, engine_values_are_validated, transmission_values_are_validated, differential_values_are_validated
WheelSettings friction curves finite points with increasing slip; the friction values are not bounded wheel_values_are_validated
VehicleEngineSettings::normalized_torque, every vehicle kind x within 0..=1 and at least MIN_TORQUE_CURVE_SPACING apart up to rounding x to f32, y within 0..=MAX_NORMALIZED_TORQUE (see limits.md) engine_torque_curves_stay_in_their_domain, wheeled_engines_take_only_curves_in_the_domain, motorcycle_engines_take_only_curves_in_the_domain, overflowing_tracked_drivetrains_are_refused
WheeledVehicleSettings up, forward, max pitch roll angle; collision testers unit vectors and angle ranges; tester radius below every wheel's reach vehicle_values_are_validated, collision_testers_are_validated
VehicleMut::set_driver_input, set_max_pitch_roll_angle, set_collision_tester existing ranges driver_input_drives_steers_and_brakes, invalid_vehicles_create_nothing
TrackedDriverInput track ratios magnitude within 1/MAX_RATIO..=1 (see limits.md); forward and brake as DriverInput tracked_inputs_are_validated
VehicleTrackSettings wheels, driven wheel, inertia, angular damping, max brake torque, differential ratio a wheel, a driven wheel among them; inertia within MIN_TRACK_INERTIA..=MAX_TRACK_INERTIA, the larger of the two tracks' at most MAX_TRACK_INERTIA_RATIO times the smaller (see limits.md); every wheel radius within a factor MAX_RATIO of the driven wheel's; damping and brake not negative; ratio positive tracked_settings_are_validated, track_inertias_stay_within_max_track_inertia_ratio, unequal_track_inertias_are_refused, the_widest_track_inertia_ratio_stays_finite_on_high_friction_ground, track_wheel_radii_stay_within_max_ratio_of_the_driven_wheel, invalid_tracked_vehicles_create_nothing
VehicleTrackSettings::inertia against the chassis, at create_tracked_vehicle every wheel's track mass ratio, the track's inertia over the wheel's radius squared times the chassis' largest inverse effective mass at the wheel's farthest contact over the wheel's forward/up plane, at most MAX_TRACK_MASS_RATIO (see limits.md) principal_levers_measure_the_lever_with_the_inverse_inertia, track_mass_ratio_takes_the_chassis_inertia_at_the_farthest_contact, chassis_mass_turns_body_space_into_the_principal_frame, tracks_heavy_against_their_chassis_are_refused, tracks_heavy_against_a_narrow_hull_are_refused, the_heaviest_accepted_tracks_stay_finite_on_high_friction_ground, jolt_tank_tracks_are_inside_the_track_mass_ratio
TrackedVehicleSettings engine, transmission and tracks together the track drive envelope at most 1e30 (see limits.md) tracked_drive_envelope_bounds_the_drivetrain, overflowing_tracked_drivetrains_are_refused, the_strongest_light_tracks_stay_finite, the_strongest_tracks_with_the_widest_radius_ratio_stay_finite, the_strongest_tracks_on_the_widest_curve_stay_finite
VehicleMut::set_engine, set_transmission the creation rules of the vehicle's kind, against its wheels, the rest of its drivetrain and its current tester; same forward and reverse gear counts and clutch release time (VehicleError::FixedAtCreation); for a tank, the track drive envelope from the track speeds earlier configurations allowed (see limits.md) invalid_live_drivetrains_change_nothing, overflowing_live_engines_and_transmissions_are_refused, gear_counts_and_clutch_release_time_are_fixed_at_creation, clutch_release_time_refusal_during_a_countdown, track_speeds_from_rest_match_the_envelope_and_never_shrink, a_reached_speed_can_refuse_a_change_valid_from_rest, live_tank_engine_changes_after_fast_driving_step_finitely
VehicleMut::set_differentials the creation rules of the differentials and the limited slip ratio, against the vehicle's wheels, engine, transmission and current tester invalid_live_differentials_change_nothing
VehicleMut::set_tracks the creation rules of the tracks, the track mass ratio against the chassis as created, and the track drive envelope as for set_engine; same wheels and driven wheel (VehicleError::FixedAtCreation) track_inertia_bounded_by_the_chassis, track_wheels_are_fixed_at_creation, live_tracks_after_fast_driving_step_finitely, rescaled_weighted_bounds_take_either_operand, successive_unequal_inertia_changes_cover_every_earlier_state
TireFriction returned by a tire max impulse callback each coefficient clamped to 0..=MAX_FRICTION, NaN to 0, then times the suspension impulse as in Jolt's default; the largest equals friction curves of MAX_FRICTION on ground of MAX_FRICTION, the same grip bound (see limits.md) coefficients_are_clamped_to_the_friction_bounds, outputs_are_clamped_to_the_friction_bounds, the_largest_friction_stays_finite, the_largest_friction_of_a_callback_matches_the_largest_friction_curves
TrackedWheelSettings::longitudinal_friction, lateral_friction 0..=MAX_FRICTION tracked_settings_are_validated
TrackedWheelSettings position, force point, directions, lengths, spring, radius, width the WheelSettings rules above tracked_wheels_share_the_wheel_rules
MotorcycleSettings::max_lean_angle 0..=MotorcycleSettings::MAX_LEAN_ANGLE (80°, see limits.md) motorcycle_settings_are_validated, max_lean_angle_is_80_degrees
MotorcycleSettings::lean_spring_constant, lean_spring_damping finite, not negative, and (k·π + c·MAX_ANGULAR_VELOCITY_CHANGE) times the chassis' largest principal inverse inertia within MAX_ANGULAR_ACCELERATION (see limits.md) lean_spring_rule_boundary, motorcycle_settings_are_refused, lean_spring_at_its_bound_steps_finitely
MotorcycleSettings::lean_smoothing_factor 0..=1 motorcycle_settings_are_validated
MotorcycleSettings::lean_spring_integration_coefficient exactly 0 (VehicleError::LeanSpringIntegrationNotSaved) motorcycle_settings_are_validated, motorcycle_settings_are_refused
MotorcycleSettings wheels exactly two, apart along the vehicle's forward in plain and fused f32 and in f64 motorcycle_settings_are_validated
SpringSettings::StiffnessAndDamping MAX_SPRING_COEFFICIENT stiffness_springs_are_bounded_by_the_coefficient
SpringSettings::FrequencyAndDamping in RagdollSettings::new, new_stabilized B·ω² and 2·B·ζ·ω at most MAX_SPRING_COEFFICIENT motor_springs_are_bounded_by_the_parts_effective_mass, motor_spring_of_1e20_hz_is_rejected
MotorSettings::force_limits, torque_limits; angle limits finite, min <= max; Jolt clamps the motor impulse to dt · limit motors_and_springs_are_validated, swing_twist_limits_are_validated, hinge_limits_are_validated, six_dof_limits_are_validated
constraint frame points MAX_POSITION constraint_frame_points_are_bounded, constraint_targets_are_bounded
the points where PhysicsWorld::create_constraint holds a dynamic body (frame points, automatic points, every point of a path); no setter moves them, and a rebase moves them with their bodies lever-arm ratio at most MAX_LEVER_ARM_RATIO lever_arms_are_bounded_by_the_bodies_size, far_and_light_constraint_points_are_refused, constraints_at_the_lever_arm_bound_step_finitely
SpringSettings::FrequencyAndDamping in PhysicsWorld::create_constraint, ConstraintMut::<DistanceConstraint>::set_limits_spring, ConstraintMut::<HingeConstraint>::set_motor_settings, set_limits_spring B·ω² and 2·B·ζ·ω at most MAX_SPRING_COEFFICIENT, B from the constraint's two bodies world_constraint_springs_are_bounded_by_the_bodies_effective_mass
DistanceRange::Range, ConstraintMut::<DistanceConstraint>::set_distance 0 <= min <= max <= MAX_SHAPE_EXTENT constraint_targets_are_bounded
ConstraintMut::<HingeConstraint>::set_target_angle [-π, π]; Jolt clamps it to the limits constraint_targets_are_bounded
ConstraintMut::<HingeConstraint>::set_target_angular_velocity MAX_ANGULAR_VELOCITY constraint_targets_are_bounded
ConstraintMut::<HingeConstraint>::set_limits Jolt's hinge ranges, min == max only with a soft spring hinge_setters_check_their_values
ConstraintMut::<HingeConstraint>::set_max_friction_torque finite, at least 0; Jolt clamps the friction impulse to dt · limit constraint_friction_at_f32_max_steps_finitely
SliderConstraintSettings::limits, ConstraintMut::<SliderConstraint>::set_limits, remove_limits min in [-MAX_SHAPE_EXTENT, 0], max in [0, MAX_SHAPE_EXTENT], min == max only with a soft spring slider_cone_swing_twist_and_six_dof_targets_are_bounded
ConstraintMut::<SliderConstraint>::set_target_position MAX_SHAPE_EXTENT; Jolt clamps it to the limits slider_cone_swing_twist_and_six_dof_targets_are_bounded
ConstraintMut::<SliderConstraint>::set_target_velocity MAX_LINEAR_VELOCITY slider_cone_swing_twist_and_six_dof_targets_are_bounded
SliderConstraintSettings::max_friction_force, ConstraintMut::<SliderConstraint>::set_max_friction_force, ConstraintMut::<SwingTwistConstraint>::set_max_friction_torque finite, at least 0 slider_and_swing_twist_friction_at_f32_max_steps_finitely
SpringSettings::FrequencyAndDamping in the slider, swing-twist and six-DOF motor and limit spring setters of ConstraintMut as for create_constraint slider_swing_twist_and_six_dof_motor_springs_are_bounded
ConeConstraintSettings::new half angle, ConstraintMut::<ConeConstraint>::set_half_cone_angle [0, π], as Jolt asserts slider_cone_swing_twist_and_six_dof_targets_are_bounded
ConstraintMut::<SwingTwistConstraint>::set_target_angular_velocity_cs, ConstraintMut::<SixDofConstraint>::set_target_angular_velocity_cs MAX_ANGULAR_VELOCITY slider_cone_swing_twist_and_six_dof_targets_are_bounded
ConstraintMut::<SwingTwistConstraint>::set_target_orientation_cs, ConstraintMut::<SixDofConstraint>::set_target_orientation_cs finite unit quaternion; Jolt clamps it to the limits slider_cone_swing_twist_and_six_dof_targets_are_bounded
ConstraintMut::<SixDofConstraint>::set_target_velocity_cs MAX_LINEAR_VELOCITY slider_cone_swing_twist_and_six_dof_targets_are_bounded
ConstraintMut::<SixDofConstraint>::set_target_position_cs MAX_SHAPE_EXTENT per axis slider_cone_swing_twist_and_six_dof_targets_are_bounded
GearConstraintSettings::new, teeth ratio 1..=MAX_GEAR_RATIO (see GearConstraintSettings and MAX_GEAR_RATIO for both bounds) coupling_ratios_are_bounded, ratios_at_the_bound_step_finitely, behaviour at the bound in tests/constraints.rs
RackAndPinionConstraintSettings::new, teeth ratio magnitude within 1 / MAX_RATIO..=MAX_RATIO; teeth length positive within MAX_SHAPE_EXTENT coupling_ratios_are_bounded, ratios_at_the_bound_step_finitely
PulleyConstraintSettings::ratio positive, within 1 / MAX_RATIO..=MAX_RATIO pulley_ratio_and_lengths_are_bounded, pulleys_at_the_ratio_bound_step_finitely
PulleyLength::Range, ConstraintMut::<PulleyConstraint>::set_length 0 <= min <= max <= (1 + ratio) · MAX_SHAPE_EXTENT pulley_ratio_and_lengths_are_bounded
PulleyConstraintSettings::new body and fixed points MAX_POSITION; a rebase moves fixed points as re-expressed state, checked finite only pulley_ratio_and_lengths_are_bounded
HermitePath::new points 2 to HermitePath::MAX_POINTS; positions and tangents within MAX_SHAPE_EXTENT per axis; unit normal invalid_paths_are_rejected, path_inputs_are_bounded
HermitePath::new segments chord at least 1 mm; derivative along the chord at least twice its bound along the normal and above an f32 margin, so Jolt's normal stays unit invalid_paths_are_rejected, path_validation_accepts_its_boundary
PathConstraintSettings::path_position, path_rotation, path_fraction MAX_SHAPE_EXTENT per axis; unit quaternion; [0, max_fraction] path_inputs_are_bounded
PathConstraintSettings::max_friction_force, ConstraintMut::<PathConstraint>::set_max_friction_force finite, at least 0 path_motor_springs_and_friction_are_bounded
PathConstraintSettings::position_motor, ConstraintMut::<PathConstraint>::set_position_motor_settings springs as for create_constraint path_motor_springs_and_friction_are_bounded
ConstraintMut::<PathConstraint>::set_target_velocity, set_target_path_fraction MAX_LINEAR_VELOCITY; [0, max_fraction] path_inputs_are_bounded
ConstraintRef::<PathConstraint>::closest_fraction point within MAX_SHAPE_EXTENT per axis, finite hint path_inputs_are_bounded
SwingTwistConstraintSettings::max_friction_torque, HingeConstraintSettings::max_friction_torque, SixDofConstraintSettings::max_friction finite, at least 0; Jolt clamps the friction impulse to dt · limit and applies no more than stops the relative motion swing_twist_limits_are_validated, hinge_limits_are_validated, six_dof_limits_are_validated
SixDofAxis::Limited on a translation axis finite, min < max, within MAX_SHAPE_EXTENT six_dof_limits_are_validated, six_dof_translation_limits_at_the_bound_step_finitely
RagdollSettings::new, new_stabilized part masses MIN_MASS..=MAX_MASS, also for kinematic parts (RagdollMut::set_motion_type can make them dynamic) part_masses_and_velocities_are_bounded
RagdollMut::set_pose, drive_to_pose_using_motors root offset and positions within MAX_POSITION poses_are_validated
RagdollMut::drive_to_pose_using_kinematics pose as above; every part's velocity, as Jolt computes it, within MAX_LINEAR_VELOCITY and MAX_ANGULAR_VELOCITY, checked for all parts before any changes poses_are_validated, kinematic_drive_is_bounded_by_the_velocities_it_implies
RagdollMut::set_linear_and_angular_velocity MAX_LINEAR_VELOCITY, MAX_ANGULAR_VELOCITY part_masses_and_velocities_are_bounded
SkeletonMapper::new neutral poses as for RagdollMut::set_pose (re-expressed translations stay within 2 MAX_POSITION (1 + 2^-22)); locked joints exist and are neither joint 0 nor the joint the ragdoll root maps to mappings_are_validated, selected_translation_locks; src/ragdoll/mapper/tests.rs: neutral_poses_are_validated (neutral poses at opposite edges of the frame, with the first map), reexpressed_translations_round_past_twice_the_frame_by_ulps, locks_are_validated
SkeletonMapper::map ragdoll pose as for set_pose; local translation components within MAX_POSITION, finite unit rotations (normalised before Jolt sees them); each chain's ragdoll direction exactly zero or at least MIN_MAPPED_CHAIN_LENGTH, its animation direction at least that after the rounding allowance; both directions at most 1e18 m and their product at most 4e18 m², a norm bound on the chain's products at most 1e30 (none reachable from the safe API's inputs); the mapped pose within MAX_POSITION poses_are_validated_per_call, rotations_at_the_tolerance_edge_are_normalised, degenerate_chains_are_refused, outputs_are_validated; src/ragdoll/mapper/tests.rs: a_long_twisting_chain_maps, the_deepest_spiral_chains_map; crates/oxijolt-sys/tests/skeleton_mapper_smoke.rs: map2_refuses_degenerate_chains_and_writes_nothing, map2_accepts_a_long_twisting_chain, map2_bounds_long_actual_directions_against_a_zero_desired_one
SkeletonMapper::map_reverse animation pose as for set_pose; the mapped pose within MAX_POSITION poses_are_validated_per_call, outputs_are_validated
Shape::new_box*, new_sphere, new_cylinder*, new_capsule dimensions within MAX_SHAPE_EXTENT primitive_extents_are_bounded
Shape::new_compound, new_offset_center_of_mass positions and offset within MAX_SHAPE_EXTENT; local bounds within it decorated_and_compound_extents_are_bounded
Shape::new_compound sub-shape ids Jolt's 32-bit width; no one-child compound starting at bit 32 (it would push its 0-bit index at bit 32) src/shape/tests.rs: a_one_child_compound_at_bit_32_is_refused, sub_shape_id_arithmetic_follows_jolt, height_field_ids_reach_exactly_32_bits, shared_shapes_are_walked_once, walked_widths_follow_jolt
MutableCompound::from_children, add_shape, modify_shape positions and rotations the rules of Shape::new_compound: positions within MAX_SHAPE_EXTENT, finite unit rotations src/shape/mutable/tests.rs: refused_edits_change_nothing
MutableCompound::remove_shape, modify_shape index below sub_shape_count src/shape/mutable/tests.rs: every_edit_checks_its_index
MutableCompound child count at most u32::MAX - 3 (Jolt's (count + 3) >> 2 block count) src/shape/mutable/tests.rs: child_count_is_bounded_by_jolts_block_arithmetic
MutableCompound sub-shape ids the rules of Shape::new_compound, checked before every edit src/shape/mutable/tests.rs: sub_shape_ids_are_checked_before_every_edit, refused_edits_walk_a_shared_child_once, an_empty_holder_has_jolts_width
Shape::new_compound, MutableCompound::from_children, add_shape, modify_shape, to_shape expanded tree at most MAX_EXPANDED_SUB_SHAPES shapes, a shared child counted at every use (ShapeError::TooManySubShapes) src/shape/tests.rs: compounds_above_the_expansion_bound_are_refused; src/shape/mutable/tests.rs: edits_above_the_expansion_bound_are_refused
MutableCompound::to_shape at least one child; local bounds within MAX_SHAPE_EXTENT after the centre of mass moves src/shape/mutable/tests.rs: removing_to_zero_and_adding_again_works, extent_is_checked_after_the_centre_of_mass_moves
Shape::new_height_field local bounds within MAX_SHAPE_EXTENT height_field_extent_is_bounded
Shape::new_plane, new_plane_with_material normal a finite unit vector; constant (absolute) and positive half extent within MAX_SHAPE_EXTENT; Jolt's local bounds within it (see limits.md) plane_inputs_are_validated, a_tilted_plane_is_checked_against_jolts_bounds, src/shape/plane.rs: bounds_reach_half_extent_around_the_plane_and_behind_it
HeightFieldSettings, CompoundChild::rotation existing ranges invalid_height_fields_are_rejected, empty_or_invalid_compounds_are_rejected
Shape::new_box_with_material, new_sphere_with_material, new_capsule_with_material, new_cylinder_with_material the plain sibling's rules convex_constructors_apply_the_plain_rules
HeightFieldSettings::materials the rules of new_height_field; material count 1..=256, (n - 1)^2 indices, each below the count height_field_material_lists_are_validated
Shape::new_convex_hull points at least 4; at most i32::MAX; each within MAX_SHAPE_EXTENT; Jolt's initial triangle, a needle bound and a slab bound (see limits.md); bounds within MAX_SHAPE_EXTENT too_few_points_are_refused, points_must_be_finite_and_within_the_extent, points_without_a_triangle_are_degenerate, needle_rule_compares_the_rounding_lever_with_the_tolerance, slab_rule_counts_coplanar_distances, thin_slabs_near_the_origin_build_down_to_a_fraction_of_a_millimetre, far_clouds_need_more_thickness, needles_too_thin_for_the_hull_builder_are_degenerate
Shape::new_convex_hull_with_convex_radius convex radius finite, at least 0 convex_radius_must_be_finite_and_not_negative
Shape::restore_binary_state bytes the header's magic, format version, flags and build id equal this build's, the payload length equals the bytes after the header, the XXH64 checksum matches; joltc's record checks; the restored shape within MAX_SHAPE_EXTENT, Jolt's sub-shape ids and MAX_EXPANDED_SUB_SHAPES (see limits.md) bytes_without_the_header_are_not_binary_state, bytes_of_another_build_are_refused, every_truncation_is_refused_as_truncated, bytes_after_the_payload_are_refused, payload_bit_flips_are_refused_as_corrupt, a_record_joltc_refuses_behind_a_valid_checksum_is_rejected, a_restored_shape_beyond_the_extent_is_malformed
Shape::new_mesh* vertices and indices at least one of each, at most i32::MAX; every vertex within MAX_SHAPE_EXTENT, referenced or not; every index below the vertex count empty_geometry_is_refused, counts_must_fit_jolt_int, vertices_must_be_finite_and_within_the_extent, indices_beyond_the_vertices_are_refused
Shape::new_mesh* triangles twice the area at least 1.000001e-6 m² (Jolt's limit, 1e-6) plus twice a per-triangle bound of what per-axis quantization and rounding (in the mesh's and in the convex shape's space) can take from it, else dropped and reported (see limits.md); none left is MeshError::NoTriangles small_and_thin_triangles_are_dropped, slivers_that_collapse_under_quantization_are_dropped, thin_patches_survive_far_geometry, meshes_without_usable_triangles_are_refused, dropped_triangles_are_reported_with_their_area, slivers_too_thin_for_large_convex_shapes_are_dropped, the_rule_does_not_depend_on_the_corner_order, the_smallest_kept_triangles_collide_with_convex_shapes_up_to_the_extent
MeshSettings::max_convex_extent 0..=2 * MAX_SHAPE_EXTENT, default 300 m, the largest round extent at which every real prop tested in CI loses under 0.1 % of its area (see limits.md) settings_out_of_range_are_refused, the_default_convex_extent_keeps_millimetre_bevels, slivers_too_thin_for_large_convex_shapes_are_dropped, the_thinnest_kept_slivers_collide_with_convex_shapes_up_to_the_extent
MeshSettings::active_edge_cos_threshold_angle, max_triangles_per_leaf, materials [-1, 1]; 1..=8; 1 to 32 materials, one index per triangle, each below the count settings_out_of_range_are_refused, material_lists_are_checked
Shape::new_scaled scale finite; Jolt's IsValidScale; every stored mesh or heightfield triangle collidable after scaling, for the convex extent the mesh was built with (ShapeError::ThinTriangles); scaled bounds and centre of mass within MAX_SHAPE_EXTENT (see limits.md) scale_components_are_checked, jolt_scale_rules_per_shape_kind, scaled_bounds_and_centre_of_mass_stay_within_the_extent, scaled_meshes_stay_kinematic_and_collidable, translations_above_a_mesh_do_not_change_its_check, flattening_follows_the_meshs_own_coordinates, scaled_meshes_are_checked_for_the_extent_they_were_built_for
Shape::new_tapered_capsule finite, positive; half_height + max radius within MAX_SHAPE_EXTENT; not Jolt's sphere case; radius difference at most 2 · half_height · (1 - 2^-21) (see limits.md) tapered_capsule_boundaries
Shape::new_tapered_cylinder_with_convex_radius half height finite, positive; radii finite, at least 0, different, the larger at least 2^-63 m; all within MAX_SHAPE_EXTENT; bounds within it; convex radius finite, at least 0 tapered_cylinder_boundaries, radius_floor_is_two_to_the_minus_63
inertia of a moving body with an exactly diagonal tensor every moment positive with a finite inverse, or near zero diagonal_inertia_must_be_positive_unless_near_zero
PhysicsWorld::cast_ray origin MAX_POSITION query_inputs_are_bounded_by_the_frame
RayCast direction finite, not zero invalid_rays_are_rejected, a_ray_with_a_huge_finite_direction_is_cast
ShapeCast, CollideShape position MAX_POSITION query_inputs_are_bounded_by_the_frame
ShapeCast direction 2 * MAX_POSITION per axis query_inputs_are_bounded_by_the_frame
PhysicsWorld::collide_point point MAX_POSITION; filter valid for the world invalid_points_and_filters_are_rejected
Shape::collide_point point each component within MAX_SHAPE_EXTENT invalid_points_and_filters_are_rejected
ShapeCast::target_distance ShapeCast::MAX_TARGET_DISTANCE target_distance_at_the_bound_gives_a_finite_depth
CollideShape::max_separation_distance 0..=MAX_SHAPE_EXTENT query_inputs_are_bounded_by_the_frame
SoftBodySharedSettingsBuilder::build vertices at least one; position within MAX_SHAPE_EXTENT per axis; velocity within MAX_LINEAR_VELOCITY; inverse mass 0 or the inverse of a mass within MIN_MASS..=MAX_MASS soft_body_shared_settings_are_bounded, invalid_vertices_are_rejected
SoftBodySharedSettingsBuilder::build total mass masses of the movable vertices (1 / w in f32, as Jolt) add up to at most MAX_MASS soft_body_total_mass_is_bounded, total_movable_mass_is_bounded
SoftBodySharedSettingsBuilder::build faces indices name vertices, three different ones; every edge at least MIN_SOFT_BODY_EDGE_LENGTH in f32; area above 0; with distance bends the vertices opposite a shared edge as far apart soft_body_shared_settings_are_bounded, invalid_faces_are_rejected, edge_lengths_are_measured_in_f32_like_jolt, distance_bends_need_separate_opposite_vertices
SoftBodyVertexAttributes compliances 0..=MAX_COMPLIANCE soft_body_shared_settings_are_bounded, attributes_are_validated
SoftBodyVertexAttributes::long_range_attachment multiplier 1..=MAX_RATIO (see limits.md) soft_body_shared_settings_are_bounded
SoftBodySharedSettingsBuilder::edge, dihedral_bend, volume indices name different vertices; compliance 0..=MAX_COMPLIANCE; edge and shared bend edge at least MIN_SOFT_BODY_EDGE_LENGTH; tetrahedron six-volume finite and not 0 in f32 soft_body_explicit_constraints_are_bounded, invalid_explicit_constraints_are_rejected
SoftBodySettings position, rotation, object layer, friction, restitution, gravity factor as for BodySettings soft_body_settings_are_bounded
SoftBodySettings::num_iterations 1..=SoftBodySettings::MAX_ITERATIONS; Jolt divides the step by it soft_body_settings_are_bounded
SoftBodySettings::linear_damping, max_linear_velocity, vertex_radius finite, at least 0; (0, MAX_LINEAR_VELOCITY]; 0..=MAX_SHAPE_EXTENT soft_body_settings_are_bounded
SoftBodySettings::pressure 0..=MAX_SOFT_BODY_PRESSURE; above 0 only when the faces enclose a volume large enough for it (see limits.md) soft_body_settings_are_bounded, pressure_at_the_bound_steps_finitely, pressure_needs_a_volume_for_its_faces, a_sliver_at_the_pressure_bound_steps_finitely
PhysicsWorld::create_soft_body vertices (positions about the origin, masses) without a kinematic vertex: smallest principal moment of the inertia at least MIN_INERTIA_RATIO (4.8e-4) of its Frobenius norm after Jolt's f32 error, or an exactly diagonal tensor that is near zero or has every moment above 1e-30 (see limits.md) soft_body_inertia_is_checked_at_creation, soft_body_inertia_at_its_bound_decomposes
SoftBodyMut::set_vertex_velocity MAX_LINEAR_VELOCITY soft_body_vertex_writes_are_bounded_and_rejection_changes_nothing
SoftBodyMut::set_vertex_inverse_mass 0 or the inverse of a mass within MIN_MASS..=MAX_MASS; total movable mass at most MAX_MASS; the force accumulated this step within the soft body force bound for the new inverse masses; the inertia rule of create_soft_body at the current vertex positions soft_body_vertex_writes_are_bounded_and_rejection_changes_nothing, unpinning_cannot_release_an_accumulated_force, unpinning_checks_the_inertia_at_the_current_positions
SoftBodyMut::move_kinematic_vertex target within MAX_POSITION; a time step step accepts; the implied velocity within MAX_LINEAR_VELOCITY soft_body_vertex_writes_are_bounded_and_rejection_changes_nothing
BodyMut::add_force on a soft body accumulated ` F
ContactSettings::set_combined_friction (in a ContactListener) 0..=MAX_FRICTION contact_settings_setters_accept_their_range_and_refuse_beyond
ContactSettings::set_combined_restitution 0..=1 contact_settings_setters_accept_their_range_and_refuse_beyond
ContactSettings::set_inverse_mass_scale1, set_inverse_mass_scale2, set_inverse_inertia_scale1, set_inverse_inertia_scale2; the SoftBodyContactSettings scales 0 or MIN_CONTACT_SCALE..=1 (see limits.md) contact_settings_setters_accept_their_range_and_refuse_beyond, soft_body_contact_settings_setters_keep_scales_in_range, contact_scales_at_their_floor_step_finitely
ContactSettings::set_is_sensor stays true for a contact with a sensor body, as Jolt asserts a_contact_with_a_sensor_body_stays_a_sensor_contact
ContactSettings returned by a ContactListener every rule above, checked again against the contact the listener was called for; a failing value is not applied and is reported in WorldEvents::rejected_contact_settings settings_are_checked_again_against_the_contact_that_takes_them, settings_moved_to_a_contact_they_do_not_fit_are_rejected
ContactSettings::set_relative_linear_surface_velocity, set_relative_angular_surface_velocity MAX_LINEAR_VELOCITY, MAX_ANGULAR_VELOCITY, and len(v) + len(ω) · R <= MAX_LINEAR_VELOCITY (see limits.md) surface_velocities_are_bounded_alone_and_together, a_conveyor_moves_a_resting_cube
BodyVelocity::set_linear_velocity, set_angular_velocity (in a CharacterContactListener) finite, MAX_LINEAR_VELOCITY, MAX_ANGULAR_VELOCITY (see limits.md) adjusted_velocities_outside_the_limits_are_refused, a_far_lever_adjusted_velocity_stays_finite
GroupFilterTableBuilder::new, disable_collision, enable_collision, GroupFilterTable::is_collision_enabled 1..=GroupFilterTable::MAX_SUB_GROUPS sub groups; sub groups below the count, and different for an edit (see limits.md) builder_and_group_boundaries, enabling_a_disabled_pair_makes_it_collide_again
CollisionGroup::new group id at most CollisionGroup::MAX_GROUP_ID, sub group below the table's count builder_and_group_boundaries
DebugLineSettings (feature debug-renderer) centre within MAX_POSITION, radius at most twice it center_and_radius_are_bounded_by_the_frame

Covered by tests only

The asserts leg of CI runs every test with Jolt's assertions. These paths are exercised there by scenes with inputs at their bounds; no derivation backs them:

  • contact and constraint impulses the solver generates: spheres of MIN_MASS and MAX_MASS colliding head-on at the velocity bounds, restitution 1, friction at MAX_FRICTION including a speculative contact with zero normal impulse, motors at the spring bound, six-DOF translation limits at the extent bound between parts of both mass extremes, suspension springs and anti-roll bars at their bounds (bodies_at_every_bound_step_finitely, friction_at_the_bound_keeps_contacts_finite, six_dof_translation_limits_at_the_bound_step_finitely, vehicle_springs_and_anti_roll_bar_at_their_bounds_step_finitely, motor_springs_at_the_coefficient_bound_drive_finitely);
  • impulses at a lever arm on the lightest bodies: the weight impulse of a character of MAX_MASS at MAX_WEIGHT_IMPULSE on the edge of a 6 cm cube of MIN_MASS, the cube that turns fastest (character_weight_impulse_at_a_lever_arm_is_bounded), and a box of MIN_MASS pressed on its floor and pushed at the velocity bound by such a character (character_at_its_bounds_pushes_the_lightest_body);
  • query arithmetic: rays, shape casts and collisions from frame corners (query_inputs_are_bounded_by_the_frame) and a sphere at the extent bound cast across the frame and collided with separations up to the extent bound (queries_with_shapes_at_the_extent_bound_stay_finite);
  • world constraints: gears at both ends of 1..=MAX_GEAR_RATIO, racks and pinions and pulleys at both MAX_RATIO bounds between bodies of both mass extremes, one of them turning or sliding at the velocity bound (ratios_at_the_bound_step_finitely, pulleys_at_the_ratio_bound_step_finitely); motor and limit springs accepted at the effective-mass bound and rejected one representable frequency above it (world_constraint_springs_are_bounded_by_the_bodies_effective_mass, slider_swing_twist_and_six_dof_motor_springs_are_bounded, path_motor_springs_and_friction_are_bounded); targets at their bounds (constraint_targets_are_bounded, slider_cone_swing_twist_and_six_dof_targets_are_bounded, path_inputs_are_bounded); hinge, slider, swing-twist and path friction of f32::MAX on bodies moving at the velocity bounds (constraint_friction_at_f32_max_steps_finitely, slider_and_swing_twist_friction_at_f32_max_steps_finitely, path_motor_springs_and_friction_are_bounded); and a path segment at the margin of the segment check stepped end to end with every rotation constraint (path_validation_accepts_its_boundary); points that hold a dynamic body at MAX_LEVER_ARM_RATIO: a ball joint and a hinge on a static body, and a weld, a six-DOF joint with every axis fixed and a swing-twist joint with zero ranges on a static body or between two bodies, each holding a 1 g, 6 cm cube or a 1 kg, 1 m cube at the velocity bounds under gravity (constraints_at_the_lever_arm_bound_step_finitely);
  • a motorcycle lean spring at the bound of its rule on a 1 g chassis of 7 cm, turning at the smallest, a 60 Hz and the largest step (lean_spring_at_its_bound_steps_finitely);
  • buoyancy on 500 seeded bodies of seven shape kinds across the surface, at speeds up to the bounds, with gravity factors up to 1000 of either sign, drags up to 1e30 and both step bounds: every call is accepted or refused, and the velocities stay finite and within the bounds after the call and after a step (seeded_calls_are_accepted_or_refused_and_stay_finite).

Not covered

  • Collision estimates are Jolt's estimate for an isolated pair. More than two bodies in contact, the contact's mass and inertia scales, surface velocities, locked axes, the speed limits and the solver's removal of the step's gravity from a bounce are not part of them; a speculative contact is estimated as touching, and a contact the continuous stage finds is estimated from velocities after the solve. The tests pin these limits (locked_axes_are_not_part_of_the_estimate, estimates_use_the_settings_jolt_resolves_the_contact_with, under_gravity_the_estimated_bounce_is_faster_by_restitution_g_dt, a_contact_found_by_the_continuous_stage_is_estimated) rather than bound them.

  • The spin a buoyancy impulse gives through the lever of its centre of buoyancy is clamped to MAX_ANGULAR_VELOCITY right after the call, not refused (see limits.md).

  • State the simulation produces itself is not an input and is not checked again: a body Jolt carries out of the frame, the positions a rebase computes (only checked to be finite), or a character state restored with CharacterMut::restore_state, which can only come from CharacterRef::save_state.

  • Bodies with a principal inverse inertia above √3 · 1e6, such as a light needle-thin shape or a centre of mass far from the shape. PhysicsWorld::create_body bounds no inverse inertia from above: an exactly diagonal tensor (an unrotated shape, or a centre of mass moved along a principal axis) only needs finite inverse moments, and the rigid body inertia floor (see limits.md) bounds how badly conditioned any other tensor is, not how small it is. The boundary tests of that floor step slender bodies for two ticks without contacts or impulses, so impulses at a lever arm on such a body, including a character's weight impulse, are neither derived nor tested. The same holds for the suspension effective mass Jolt forms from a wheel's force point and the chassis's inverse inertia (VehicleConstraint.cpp:448-451).

  • Constraints whose solver diverges for reasons the lever-arm ratio does not measure. In the asserts build Jolt then asserts that a squared velocity is finite (MotionProperties.inl:28 or :38); in the release build the joint tears apart by metres and the state can become NaN: Jolt's velocity clamp scales a velocity whose squared length overflows to zero, turns an already infinite component into NaN (inf * 0) and lets NaN through. No impact is needed. Measured with one constraint to a static body under gravity unless stated otherwise:

    • a hinge whose pin lies off the least-inertia axis of a slender body, outside its cross section (an offset d of about twice the half thickness t or more). A 2 kg rod of 1 m by 2 cm hinged 5 cm off its axis (a lever-arm ratio of 43.5) asserted while swinging about the hinge at 10 rad/s; a 10 kg barrier arm of 3 m by 5 cm on a 5 cm bracket (ratio 12) asserted at 30 rad/s. In the release build both became NaN within a few hundred steps of such a swing (the step depends on the scene); a 1 m rod 1 cm thick with the pin 5 cm beside it along the hinge line asserted while falling from horizontal under gravity alone. On 1 m rods swung at up to 47 rad/s, t = 5 mm failed from d = 1 cm, t = 1 cm from 2 cm, t = 2 cm only at 10 cm, and t = 5 cm not up to 10 cm;
    • chains of hinges with non-parallel axes, also between cubes: of 100 seeded chains of 3 to 10 cubes, 3 asserted at kicks of 15 m/s and 1.4 rad/s per body at lever-arm ratios of 10 to 100, and 18 at ratios of 100 to 500; in the release build 2 of 100 chains became NaN at 15 m/s and 31 of 100 at 50 m/s;
    • a light body held by two to four constraints to static anchors, also without a hinge (point and fixed, cone, distance and six-DOF, ...): of 300 seeded scenes at 0.3 to 1 of the lever-arm bound, 24 asserted at the velocity bounds with every constraint kind and 8 without hinges, 3 at a tenth of the bounds and none at 3 %.

    The same probes found no assert and no NaN for a 2 m by 1 m by 5 cm door hinged at its edge, capsule limbs on hinges, a rod hinged on its axis, or the 12-capsule test ragdoll, at kicks up to 499 m/s and 47 rad/s, but their joints still opened by more than 0.5 m: of 24 kicks at 150 m/s, 8 for the door, 10 for the rod and 9 for a forearm or shin capsule, and at 499 m/s 16, 24 and 19, up to 3.3 m for the door, 4.1 m for the rod and 7.3 m for the capsules; one of 24 exploded ragdolls opened by 1 m at 150 m/s. A six-DOF joint with the hinge's free axis did not assert on the slender bodies but let the joint drift apart by 0.2 to 3.3 m while swinging and up to 6.9 m under kicks of 50 m/s, so it is no workaround. No bound in oxijolt::limits excludes these cases.

  • A slider adds the distance travelled along its axis to the lever of body 1 (SliderConstraint.cpp), which MAX_LEVER_ARM_RATIO checks only at creation; with a dynamic body 1 and a long travel the lever grows beyond the bound.

  • Inputs that are only checked to be finite or ordered, as the table above says: ray directions, damping, motor force and torque limits, ragdoll joint friction (world constraint friction is probed as above), wheel friction curves and the wheel and drivetrain values that only have to give finite step coefficients.

  • A soft body with pressure whose volume shrinks after creation (crushed, or its vertices moved or recentred by Jolt so that an open mesh encloses less): Jolt divides the pressure by the volume of every sub-step (SoftBodyMotionProperties.cpp:300-307), and the creation check holds only for the start geometry.

  • Soft body constraint stability: MAX_COMPLIANCE keeps Jolt's compliance terms finite, not the solver convergent. Measured: a 2 m cube of 1 g vertices, three of them kinematic, with six tetrahedral volume constraints of compliances 0 to 1e20, per-vertex attributes with edge and shear compliances up to 1e20 and LRA multipliers up to 1e4, distance bends, 100 iterations, no damping, restitution 1, a vertex speed limit of 1 m/s, one vertex given 155 m/s and an accepted force of 3.7e6 N, had NaN vertices after its first step in the release build and asserted that a squared velocity is finite (MotionProperties.inl:28) in the asserts build. With a tenth of the force, 5 iterations, no volume constraints or uniform attributes it stayed finite. No bound in oxijolt::limits excludes it. Two more seeded scenes of the same kind failed in the asserts build: a cube of 1 g vertices with six volume constraints, 37 iterations, a step of 0.1 s, friction 1000, a vertex radius of 2000 m, a force of 3.7e6 N and a vertex unpinned to 1 kg asserted at MotionProperties.inl:28; a cube with pressure 1e5 under gravity of about 1000 m/s², pushed by repeated forces of 3.8e9 N and resting against rigid bodies (without them it did not fail), grew bounds beyond cLargeFloat (QuadTree.cpp:68).

  • A tracked vehicle's tracks pulled by the ground (TrackedVehicleController.cpp:394-406) at 1 s steps, or with a dynamic body under the wheels. At 1 s steps the chassis reached Jolt's angular velocity clamp from a track mass ratio of 0.32 at game friction, and went NaN from 0.062 with tire and ground friction 1000, both below what MAX_TRACK_MASS_RATIO accepts; a body under the wheels adds its own inverse mass, which the ratio does not count (limits.md).

  • A motorcycle's lean compensation divides by the sum of both wheels' suspension impulses times the chassis' inverse mass (MotorcycleController.cpp:246); a small positive impulse can make that product underflow to 0. It was not seen in the tests.

  • RagdollSettings::new_stabilized reports Jolt's Stabilize failing to decompose an inertia tensor as an error, but Jolt asserts on that path first (Ragdoll.cpp:158).

  • The assertion errors == EPhysicsUpdateError::None at the end of every step that drops contacts (PhysicsSystem.cpp:679) is intentional: PhysicsWorld::step returns the same errors in its StepReport, and oxijolt's assertion handler lets the process continue for this assertion only.