Skip to main content

bevy_rapier2d/plugin/context/
mod.rs

1//! These are components used and modified during a simulation frame.
2
3pub mod systemparams;
4
5use bevy::prelude::*;
6use rapier::geometry::{ContactData, ContactManifoldData};
7use rapier::parry::query::{PersistentQueryDispatcher, QueryDispatcher};
8use std::collections::HashMap;
9use std::sync::RwLock;
10
11use rapier::prelude::{
12    Aabb, CCDSolver, ColliderHandle, ColliderSet, CollisionPipeline, EventHandler, FeatureId,
13    ImpulseJointHandle, ImpulseJointSet, IntegrationParameters, IslandManager,
14    MultibodyJointHandle, MultibodyJointSet, NarrowPhase, PhysicsHooks, PhysicsPipeline,
15    QueryFilter as RapierQueryFilter, QueryPipeline, QueryPipelineMut, Ray, Real, RigidBodyHandle,
16    RigidBodySet, RigidBodyType, SoftBodyHandle, SoftBodySet,
17};
18
19use crate::geometry::{
20    AsShape, NonlinearMotion, PointProjection, RayIntersection, ShapeCastHit, ShapeClosestPoints,
21    ShapeContact,
22};
23use crate::math::{Rot, Vect};
24use crate::pipeline::{CollisionEvent, ContactForceEvent, EventHandlerFanOut, EventQueue};
25use bevy::prelude::{Entity, GlobalTransform, Query};
26use rapier::geometry::Collider as RapierCollider;
27use rapier::parry::partitioning::Bvh;
28use rapier::parry::query::ClosestPoints;
29use rapier::parry::shape::CompositeShapeRef;
30
31use crate::control::{CharacterCollision, MoveShapeOptions, MoveShapeOutput};
32use crate::dynamics::{
33    ImpulseJointImpulses, InverseKinematicsOption, MultibodyJointState, RapierSoftBody,
34    RapierSoftBodyTearEvent, TransformInterpolation,
35};
36use crate::parry::query::details::ShapeCastOptions;
37use crate::pipeline::{PhysicsQuarantineEvent, SoftBodyTearResult};
38use crate::plugin::configuration::{BroadPhaseOptimizationStrategy, SimulationMode, TimestepMode};
39use crate::prelude::{CollisionGroups, QueryFilter, RapierRigidBodyHandle};
40use rapier::control::CharacterAutostep;
41use rapier::dynamics::ImpulseJoint as RapierImpulseJoint;
42use rapier::dynamics::{Multibody, MultibodyJoint as RapierMultibodyJoint};
43use rapier::geometry::DefaultBroadPhase;
44use rapier::math::{DVector, Jacobian};
45use std::ops::Range;
46
47#[cfg(doc)]
48use crate::prelude::{
49    systemparams::{RapierContext, ReadRapierContext},
50    ImpulseJoint, KinematicMultibodyJoint, MultibodyJoint, RevoluteJoint, TypedJoint,
51};
52
53/// Difference between simulation and rendering time
54#[derive(Component, Default, Reflect, Clone)]
55pub struct SimulationToRenderTime {
56    /// Difference between simulation and rendering time
57    pub diff: f32,
58}
59
60/// Marker component for to access the default [`ReadRapierContext`].
61///
62/// This is used as the default marker filter for [`systemparams::ReadRapierContext`] and [`systemparams::WriteRapierContext`]
63/// to help with getting a reference to the correct RapierContext.
64///
65/// If you're making a library, you might be interested in [`RapierContextEntityLink`]
66/// and leverage a [`Query`] to have precise access to relevant components (for example [`RapierContextSimulation`]).
67///
68/// See the list of full components in [`RapierContext`]
69#[derive(Component, Reflect, Debug, Clone, Copy)]
70pub struct DefaultRapierContext;
71
72/// This is a component applied to any entity containing a rapier handle component.
73/// The inner Entity referred to has the component [`RapierContextSimulation`]
74/// and others from [`crate::plugin::context`], responsible for handling
75/// its rapier data.
76#[derive(Component, Reflect, Debug, Clone, Copy, PartialEq, Eq, Hash)]
77pub struct RapierContextEntityLink(pub Entity);
78
79/// The set of colliders part of the simulation.
80///
81/// This should be attached on an entity with a [`RapierContextSimulation`]
82///
83/// With the `serde-serialize` feature, the entity-to-handle map isn't serialized: it is rebuilt
84/// from the colliders’ user-data on deserialization (see [`Self::rebuild_entity_maps`]).
85#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
86#[cfg_attr(
87    feature = "serde-serialize",
88    serde(from = "serde_shadows::RapierContextCollidersData")
89)]
90#[derive(Component, Default, Debug, Clone)]
91pub struct RapierContextColliders {
92    /// The set of colliders part of the simulation.
93    pub colliders: ColliderSet,
94    #[cfg_attr(feature = "serde-serialize", serde(skip))]
95    pub(crate) entity2collider: HashMap<Entity, ColliderHandle>,
96}
97
98impl RapierContextColliders {
99    /// Rebuilds the map from entities to collider handles from the user-data of the colliders,
100    /// which contain the bits of their entity.
101    ///
102    /// This is called automatically when deserializing this component. Call it manually after
103    /// replacing [`Self::colliders`] with a set restored in another way.
104    pub fn rebuild_entity_maps(&mut self) {
105        self.entity2collider = self
106            .colliders
107            .iter()
108            .filter_map(|(handle, co)| Some((Entity::try_from_bits(co.user_data as u64)?, handle)))
109            .collect();
110    }
111
112    /// If the collider attached to `entity` is attached to a rigid-body, this
113    /// returns the `Entity` containing that rigid-body.
114    pub fn collider_parent(
115        &self,
116        rigidbody_set: &RapierRigidBodySet,
117        entity: Entity,
118    ) -> Option<Entity> {
119        self.entity2collider
120            .get(&entity)
121            .and_then(|h| self.colliders.get(*h))
122            .and_then(|co| co.parent())
123            .and_then(|h| rigidbody_set.rigid_body_entity(h))
124    }
125
126    /// If entity is a rigid-body, this returns the collider `Entity`s attached
127    /// to that rigid-body.
128    pub fn rigid_body_colliders<'a, 'b: 'a>(
129        &'a self,
130        entity: Entity,
131        rigidbody_set: &'b RapierRigidBodySet,
132    ) -> impl Iterator<Item = Entity> + 'a {
133        rigidbody_set
134            .entity2body()
135            .get(&entity)
136            .and_then(|handle| rigidbody_set.bodies.get(*handle))
137            .map(|body| {
138                body.colliders()
139                    .iter()
140                    .filter_map(|handle| self.collider_entity(*handle))
141            })
142            .into_iter()
143            .flatten()
144    }
145
146    /// Retrieve the Bevy entity the given Rapier collider (identified by its handle) is attached to.
147    pub fn collider_entity(&self, handle: ColliderHandle) -> Option<Entity> {
148        RapierContextColliders::collider_entity_with_set(&self.colliders, handle)
149    }
150
151    // Mostly used to avoid borrowing self completely.
152    pub(crate) fn collider_entity_with_set(
153        colliders: &ColliderSet,
154        handle: ColliderHandle,
155    ) -> Option<Entity> {
156        colliders.get(handle).map(Self::entity_from_collider)
157    }
158
159    /// Retrieve the Bevy entity the given Rapier collider is attached to.
160    pub fn entity_from_collider(collider: &rapier::prelude::Collider) -> Entity {
161        Entity::from_bits(collider.user_data as u64)
162    }
163
164    /// The map from entities to collider handles.
165    pub fn entity2collider(&self) -> &HashMap<Entity, ColliderHandle> {
166        &self.entity2collider
167    }
168
169    /// The Rapier collider attached to the given `entity`, if any.
170    fn collider(&self, entity: Entity) -> Option<&rapier::geometry::Collider> {
171        self.colliders.get(*self.entity2collider.get(&entity)?)
172    }
173
174    /// Computes the world-space axis-aligned bounding box of the collider of `entity`.
175    ///
176    /// This doesn't include the contact skin. Returns `None` if `entity` has no collider.
177    #[cfg(feature = "dim2")]
178    pub fn compute_aabb(&self, entity: Entity) -> Option<bevy::shape::Aabb2d> {
179        Some(aabb_to_bevy(self.collider(entity)?.compute_aabb()))
180    }
181
182    /// Computes the world-space axis-aligned bounding box of the collider of `entity`.
183    ///
184    /// This doesn't include the contact skin. Returns `None` if `entity` has no collider.
185    #[cfg(feature = "dim3")]
186    pub fn compute_aabb(&self, entity: Entity) -> Option<bevy::shape::Aabb3d> {
187        Some(aabb_to_bevy(self.collider(entity)?.compute_aabb()))
188    }
189
190    /// Computes the world-space axis-aligned bounding box swept by the collider of `entity` when
191    /// moving from its current position to `next_position`.
192    ///
193    /// The scale of `next_position` is ignored. Returns `None` if `entity` has no collider.
194    #[cfg(feature = "dim2")]
195    pub fn compute_swept_aabb(
196        &self,
197        entity: Entity,
198        next_position: Transform,
199    ) -> Option<bevy::shape::Aabb2d> {
200        let next_position = crate::utils::transform_to_iso(&next_position);
201        Some(aabb_to_bevy(
202            self.collider(entity)?.compute_swept_aabb(&next_position),
203        ))
204    }
205
206    /// Computes the world-space axis-aligned bounding box swept by the collider of `entity` when
207    /// moving from its current position to `next_position`.
208    ///
209    /// The scale of `next_position` is ignored. Returns `None` if `entity` has no collider.
210    #[cfg(feature = "dim3")]
211    pub fn compute_swept_aabb(
212        &self,
213        entity: Entity,
214        next_position: Transform,
215    ) -> Option<bevy::shape::Aabb3d> {
216        let next_position = crate::utils::transform_to_iso(&next_position);
217        Some(aabb_to_bevy(
218            self.collider(entity)?.compute_swept_aabb(&next_position),
219        ))
220    }
221
222    /// The volume (in 3D) or area (in 2D) of the collider of `entity`.
223    ///
224    /// Returns `None` if `entity` has no collider.
225    pub fn volume(&self, entity: Entity) -> Option<Real> {
226        Some(self.collider(entity)?.volume())
227    }
228
229    /// The mass of the collider of `entity`.
230    ///
231    /// Returns `None` if `entity` has no collider.
232    pub fn mass(&self, entity: Entity) -> Option<Real> {
233        Some(self.collider(entity)?.mass())
234    }
235
236    /// The density of the collider of `entity`.
237    ///
238    /// If the collider's mass was set explicitly, this is the mass divided by the volume. Returns
239    /// `None` if `entity` has no collider.
240    pub fn density(&self, entity: Entity) -> Option<Real> {
241        Some(self.collider(entity)?.density())
242    }
243}
244
245/// Converts a Rapier AABB to a Bevy AABB.
246#[cfg(feature = "dim2")]
247fn aabb_to_bevy(aabb: Aabb) -> bevy::shape::Aabb2d {
248    bevy::shape::Aabb2d {
249        min: aabb.mins,
250        max: aabb.maxs,
251    }
252}
253
254/// Converts a Rapier AABB to a Bevy AABB.
255#[cfg(feature = "dim3")]
256fn aabb_to_bevy(aabb: Aabb) -> bevy::shape::Aabb3d {
257    bevy::shape::Aabb3d {
258        min: aabb.mins.into(),
259        max: aabb.maxs.into(),
260    }
261}
262
263/// The sets of joints part of the simulation.
264///
265/// This should be attached on an entity with a [`RapierContextSimulation`]
266///
267/// With the `serde-serialize` feature, the entity-to-handle maps aren't serialized: they are
268/// rebuilt from the joints’ user-data on deserialization (see [`Self::rebuild_entity_maps`]).
269#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
270#[cfg_attr(
271    feature = "serde-serialize",
272    serde(from = "serde_shadows::RapierContextJointsData")
273)]
274#[derive(Component, Default, Debug, Clone)]
275pub struct RapierContextJoints {
276    /// The set of impulse joints part of the simulation.
277    pub impulse_joints: ImpulseJointSet,
278    /// The set of multibody joints part of the simulation.
279    pub multibody_joints: MultibodyJointSet,
280
281    #[cfg_attr(feature = "serde-serialize", serde(skip))]
282    pub(crate) entity2impulse_joint: HashMap<Entity, ImpulseJointHandle>,
283    #[cfg_attr(feature = "serde-serialize", serde(skip))]
284    pub(crate) entity2multibody_joint: HashMap<Entity, MultibodyJointHandle>,
285}
286
287impl RapierContextJoints {
288    /// Rebuilds the maps from entities to impulse and multibody joint handles from the
289    /// user-data of the joints, which contain the bits of their entity.
290    ///
291    /// This is called automatically when deserializing this component. Call it manually after
292    /// replacing the joint sets with sets restored in another way.
293    pub fn rebuild_entity_maps(&mut self) {
294        self.entity2impulse_joint = self
295            .impulse_joints
296            .iter()
297            .filter_map(|(handle, joint)| {
298                Some((Entity::try_from_bits(joint.data.user_data as u64)?, handle))
299            })
300            .collect();
301        self.entity2multibody_joint = self
302            .multibody_joints
303            .iter()
304            .filter_map(|(handle, _, _, link)| {
305                Some((
306                    Entity::try_from_bits(link.joint().data.user_data as u64)?,
307                    handle,
308                ))
309            })
310            .collect();
311    }
312
313    /// The map from entities to impulse joint handles.
314    pub fn entity2impulse_joint(&self) -> &HashMap<Entity, ImpulseJointHandle> {
315        &self.entity2impulse_joint
316    }
317
318    /// The map from entities to multibody joint handles.
319    pub fn entity2multibody_joint(&self) -> &HashMap<Entity, MultibodyJointHandle> {
320        &self.entity2multibody_joint
321    }
322
323    /// Retrieve the entity containing the [`ImpulseJoint`] component the given Rapier impulse
324    /// joint was created from.
325    pub fn entity_from_impulse_joint(joint: &RapierImpulseJoint) -> Entity {
326        Entity::from_bits(joint.data.user_data as u64)
327    }
328
329    /// Retrieve the entity containing the [`ImpulseJoint`] component of the Rapier impulse joint
330    /// identified by the given handle.
331    pub fn impulse_joint_entity(&self, handle: ImpulseJointHandle) -> Option<Entity> {
332        self.impulse_joints
333            .get(handle)
334            .map(Self::entity_from_impulse_joint)
335    }
336
337    /// The impulses applied during the last simulation step by the [`ImpulseJoint`] of `entity`.
338    ///
339    /// This is the value written back into the [`ImpulseJointImpulses`] component after each
340    /// step. Returns `None` if `entity` has no impulse joint.
341    pub fn impulse_joint_impulses(&self, entity: Entity) -> Option<ImpulseJointImpulses> {
342        let joint = self
343            .impulse_joints
344            .get(*self.entity2impulse_joint.get(&entity)?)?;
345        Some(ImpulseJointImpulses::from_rapier(joint))
346    }
347
348    /// Iterates through the entities of all the impulse joints attaching the rigid-bodies of
349    /// `body1` and `body2` (in any order).
350    pub fn impulse_joints_between<'a>(
351        &'a self,
352        rigidbody_set: &RapierRigidBodySet,
353        body1: Entity,
354        body2: Entity,
355    ) -> impl Iterator<Item = Entity> + 'a {
356        let handles = rigidbody_set
357            .entity2body
358            .get(&body1)
359            .copied()
360            .zip(rigidbody_set.entity2body.get(&body2).copied());
361        handles.into_iter().flat_map(move |(handle1, handle2)| {
362            self.impulse_joints
363                .joints_between(handle1, handle2)
364                .map(|(_, joint)| Self::entity_from_impulse_joint(joint))
365        })
366    }
367
368    /// Iterates through the entities of all the impulse joints attached to the rigid-body of
369    /// `body`, including disabled joints.
370    pub fn attached_impulse_joints<'a>(
371        &'a self,
372        rigidbody_set: &RapierRigidBodySet,
373        body: Entity,
374    ) -> impl Iterator<Item = Entity> + 'a {
375        let handle = rigidbody_set.entity2body.get(&body).copied();
376        handle.into_iter().flat_map(move |handle| {
377            self.impulse_joints
378                .attached_joints(handle)
379                .map(|(_, _, _, joint)| Self::entity_from_impulse_joint(joint))
380        })
381    }
382
383    /// Iterates through the entities of the enabled impulse joints attached to the rigid-body
384    /// of `body`.
385    pub fn attached_enabled_impulse_joints<'a>(
386        &'a self,
387        rigidbody_set: &RapierRigidBodySet,
388        body: Entity,
389    ) -> impl Iterator<Item = Entity> + 'a {
390        let handle = rigidbody_set.entity2body.get(&body).copied();
391        handle.into_iter().flat_map(move |handle| {
392            self.impulse_joints
393                .attached_enabled_joints(handle)
394                .map(|(_, _, _, joint)| Self::entity_from_impulse_joint(joint))
395        })
396    }
397
398    /// Retrieve the entity containing the [`MultibodyJoint`] component the given Rapier
399    /// multibody joint was created from.
400    ///
401    /// This is also the entity of the rigid-body of the link containing this joint.
402    pub fn entity_from_multibody_joint(joint: &RapierMultibodyJoint) -> Entity {
403        Entity::from_bits(joint.data.user_data as u64)
404    }
405
406    /// The multibody containing the rigid-body of `entity`, and the index of the link of that
407    /// rigid-body in the multibody.
408    ///
409    /// The root rigid-body of a multibody is its link `0`. Returns `None` if the rigid-body is not
410    /// attached to any [`MultibodyJoint`].
411    pub fn multibody(
412        &self,
413        rigidbody_set: &RapierRigidBodySet,
414        entity: Entity,
415    ) -> Option<(&Multibody, usize)> {
416        let body = rigidbody_set.entity2body.get(&entity)?;
417        let link = self.multibody_joints.rigid_body_link(*body)?;
418        Some((
419            self.multibody_joints.get_multibody(link.multibody)?,
420            link.id,
421        ))
422    }
423
424    /// The multibody containing the rigid-body of `entity`, and the index of the link of that
425    /// rigid-body in the multibody, for modification.
426    ///
427    /// Note that Rapier doesn’t wake up the multibody automatically after a modification.
428    pub fn multibody_mut(
429        &mut self,
430        rigidbody_set: &RapierRigidBodySet,
431        entity: Entity,
432    ) -> Option<(&mut Multibody, usize)> {
433        let body = rigidbody_set.entity2body.get(&entity)?;
434        let link = *self.multibody_joints.rigid_body_link(*body)?;
435        Some((
436            self.multibody_joints.get_multibody_mut(link.multibody)?,
437            link.id,
438        ))
439    }
440
441    /// The entity of the root rigid-body of the multibody containing the rigid-body of `entity`.
442    pub fn multibody_root(
443        &self,
444        rigidbody_set: &RapierRigidBodySet,
445        entity: Entity,
446    ) -> Option<Entity> {
447        let (mb, _) = self.multibody(rigidbody_set, entity)?;
448        rigidbody_set.rigid_body_entity(mb.root().rigid_body_handle())
449    }
450
451    /// Iterates through the entities of the rigid-bodies of all the links of the multibody
452    /// containing the rigid-body of `entity`.
453    ///
454    /// The root comes first, and each link is yielded before its descendants. All the entities
455    /// except the root contain the [`MultibodyJoint`] attaching them to their parent link: to
456    /// remove all the joints of a multibody (like Rapier’s
457    /// `MultibodyJointSet::remove_multibody_articulations`), remove the [`MultibodyJoint`]
458    /// component from these entities (for example with `.skip(1)`).
459    pub fn multibody_links<'a>(
460        &'a self,
461        rigidbody_set: &'a RapierRigidBodySet,
462        entity: Entity,
463    ) -> impl Iterator<Item = Entity> + 'a {
464        self.multibody(rigidbody_set, entity)
465            .into_iter()
466            .flat_map(move |(mb, _)| {
467                mb.links()
468                    .filter_map(|link| rigidbody_set.rigid_body_entity(link.rigid_body_handle()))
469            })
470    }
471
472    /// The entity of the rigid-body of the parent link of the rigid-body of `entity` in its
473    /// multibody.
474    ///
475    /// Returns `None` if `entity` is the root of its multibody, or isn’t part of any multibody.
476    pub fn multibody_parent_link(
477        &self,
478        rigidbody_set: &RapierRigidBodySet,
479        entity: Entity,
480    ) -> Option<Entity> {
481        let (mb, link_id) = self.multibody(rigidbody_set, entity)?;
482        let parent = mb.link(mb.link(link_id)?.parent_id()?)?;
483        rigidbody_set.rigid_body_entity(parent.rigid_body_handle())
484    }
485
486    /// The entity of the [`MultibodyJoint`] attaching the rigid-bodies of `body1` and `body2`
487    /// (in any order), if any.
488    pub fn multibody_joint_between(
489        &self,
490        rigidbody_set: &RapierRigidBodySet,
491        body1: Entity,
492        body2: Entity,
493    ) -> Option<Entity> {
494        let handle1 = rigidbody_set.entity2body.get(&body1)?;
495        let handle2 = rigidbody_set.entity2body.get(&body2)?;
496        let (_, _, link) = self.multibody_joints.joint_between(*handle1, *handle2)?;
497        rigidbody_set.rigid_body_entity(link.rigid_body_handle())
498    }
499
500    /// Iterates through the entities of all the multibody joints attached to the rigid-body of
501    /// `body`: the joint attaching it to its parent link (if any), and the joints of its child
502    /// links.
503    pub fn attached_multibody_joints<'a>(
504        &'a self,
505        rigidbody_set: &'a RapierRigidBodySet,
506        body: Entity,
507    ) -> impl Iterator<Item = Entity> + 'a {
508        let handle = rigidbody_set.entity2body.get(&body).copied();
509        handle.into_iter().flat_map(move |handle| {
510            self.multibody_joints
511                .attached_joints(handle)
512                .filter_map(|(_, body2, _)| rigidbody_set.rigid_body_entity(body2))
513        })
514    }
515
516    /// The range of the degrees of freedom of the link of `entity` in the generalized
517    /// coordinates, velocities and displacements of its multibody.
518    ///
519    /// The degrees of freedom of a joint are its free axes, in [`JointAxis`] order.
520    ///
521    /// [`JointAxis`]: crate::dynamics::JointAxis
522    pub fn multibody_link_dofs(
523        &self,
524        rigidbody_set: &RapierRigidBodySet,
525        entity: Entity,
526    ) -> Option<Range<usize>> {
527        let (mb, link_id) = self.multibody(rigidbody_set, entity)?;
528        let link = mb.link(link_id)?;
529        let start = link.assembly_id();
530        Some(start..start + link.joint().ndofs())
531    }
532
533    /// The generalized velocities of the multibody containing the rigid-body of `entity`.
534    ///
535    /// See [`Self::multibody_link_dofs`] for the range of each link in this slice.
536    pub fn multibody_generalized_velocity(
537        &self,
538        rigidbody_set: &RapierRigidBodySet,
539        entity: Entity,
540    ) -> Option<&[Real]> {
541        let (mb, _) = self.multibody(rigidbody_set, entity)?;
542        Some(mb.generalized_velocity().data.into_slice())
543    }
544
545    /// The generalized velocities of the multibody containing the rigid-body of `entity`, for
546    /// modification.
547    ///
548    /// This wakes up the rigid-bodies of the multibody.
549    pub fn multibody_generalized_velocity_mut(
550        &mut self,
551        rigidbody_set: &mut RapierRigidBodySet,
552        entity: Entity,
553    ) -> Option<&mut [Real]> {
554        let (mb, _) = self.multibody_mut(rigidbody_set, entity)?;
555        crate::plugin::systems::wake_up_multibody(mb, &mut rigidbody_set.bodies);
556        Some(mb.generalized_velocity_mut().data.into_slice_mut())
557    }
558
559    /// The generalized velocities of the [`MultibodyJoint`] of `entity`, one per free axis in
560    /// [`JointAxis`] order, for modification.
561    ///
562    /// This is typically used to drive a [`KinematicMultibodyJoint`]. This wakes up the
563    /// rigid-bodies of the multibody.
564    ///
565    /// [`JointAxis`]: crate::dynamics::JointAxis
566    pub fn multibody_joint_velocity_mut(
567        &mut self,
568        rigidbody_set: &mut RapierRigidBodySet,
569        entity: Entity,
570    ) -> Option<&mut [Real]> {
571        let handle = *self.entity2multibody_joint.get(&entity)?;
572        let (mb, link_id) = self.multibody_joints.get_mut(handle)?;
573        crate::plugin::systems::wake_up_multibody(mb, &mut rigidbody_set.bodies);
574        let link = mb.link(link_id)?;
575        let range = link.assembly_id()..link.assembly_id() + link.joint().ndofs();
576        Some(&mut mb.generalized_velocity_mut().data.into_slice_mut()[range])
577    }
578
579    /// The state of the [`MultibodyJoint`] of `entity`.
580    ///
581    /// This is the value written back into the [`MultibodyJointState`] component after each
582    /// step.
583    pub fn multibody_joint_state(&self, entity: Entity) -> Option<MultibodyJointState> {
584        self.multibody_joint_state_from_handle(*self.entity2multibody_joint.get(&entity)?)
585    }
586
587    /// The state of the multibody joint with the given handle.
588    pub(crate) fn multibody_joint_state_from_handle(
589        &self,
590        handle: MultibodyJointHandle,
591    ) -> Option<MultibodyJointState> {
592        let (mb, link_id) = self.multibody_joints.get(handle)?;
593        let link = mb.link(link_id)?;
594        Some(MultibodyJointState::from_rapier(
595            link.joint(),
596            mb.joint_velocity(link).as_slice(),
597        ))
598    }
599
600    /// The jacobian of the link of `entity`, mapping the generalized velocities of its multibody
601    /// to the link’s world-space linear and angular velocities.
602    ///
603    /// This is computed by the last forward kinematics (see
604    /// [`Self::multibody_forward_kinematics`]), which runs at each simulation step.
605    pub fn multibody_body_jacobian(
606        &self,
607        rigidbody_set: &RapierRigidBodySet,
608        entity: Entity,
609    ) -> Option<&Jacobian<Real>> {
610        let (mb, link_id) = self.multibody(rigidbody_set, entity)?;
611        Some(mb.body_jacobian(link_id))
612    }
613
614    /// Applies displacements, in generalized coordinates, to the multibody containing the
615    /// rigid-body of `entity`.
616    ///
617    /// `displacements` must contain one value per degree of freedom of the multibody. This only
618    /// modifies the joint coordinates: call [`Self::multibody_forward_kinematics`] to update the
619    /// rigid-bodies. Returns `false` if `entity` isn’t part of a multibody or the number of
620    /// displacements doesn’t match.
621    pub fn multibody_apply_displacements(
622        &mut self,
623        rigidbody_set: &RapierRigidBodySet,
624        entity: Entity,
625        displacements: &[Real],
626    ) -> bool {
627        let Some((mb, _)) = self.multibody_mut(rigidbody_set, entity) else {
628            return false;
629        };
630        if displacements.len() != mb.ndofs() {
631            return false;
632        }
633        mb.apply_displacements(displacements);
634        true
635    }
636
637    /// Runs forward kinematics on the multibody containing the rigid-body of `entity`, and moves
638    /// its rigid-bodies to the resulting poses.
639    ///
640    /// Set `read_root_pose_from_rigid_body` if the root rigid-body was moved and the multibody
641    /// should follow. The `Transform` of the rigid-bodies are updated during the next writeback
642    /// (after the next simulation step). Returns `false` if `entity` isn’t part of a multibody.
643    pub fn multibody_forward_kinematics(
644        &mut self,
645        rigidbody_set: &mut RapierRigidBodySet,
646        entity: Entity,
647        read_root_pose_from_rigid_body: bool,
648    ) -> bool {
649        let Some((mb, _)) = self.multibody_mut(rigidbody_set, entity) else {
650            return false;
651        };
652        mb.forward_kinematics(&rigidbody_set.bodies, read_root_pose_from_rigid_body);
653        mb.update_rigid_bodies(&mut rigidbody_set.bodies, true);
654        true
655    }
656
657    /// Computes the displacements, in generalized coordinates, moving the link of `link` as close
658    /// as possible to the world-space `target` pose, with a jacobian-based inverse kinematics
659    /// solver.
660    ///
661    /// `displacements` is an output buffer: it is cleared and resized to the number of degrees of
662    /// freedom of the multibody (see [`Self::multibody_link_dofs`]), so the solver always starts
663    /// from the current configuration, then filled with the result, which can then be applied with
664    /// [`Self::multibody_apply_displacements`]. The same buffer can be reused across calls without
665    /// resetting it. Only the joints for which `joint_can_move`
666    /// returns `true` are moved; it is called with the entity of each link between the root
667    /// (included) and `link`. Returns `false` if `link` isn’t part of a multibody.
668    pub fn multibody_inverse_kinematics(
669        &self,
670        rigidbody_set: &RapierRigidBodySet,
671        link: Entity,
672        target: Transform,
673        options: &InverseKinematicsOption,
674        joint_can_move: impl Fn(Entity) -> bool,
675        displacements: &mut Vec<Real>,
676    ) -> bool {
677        let Some((mb, link_id)) = self.multibody(rigidbody_set, link) else {
678            return false;
679        };
680        displacements.clear();
681        displacements.resize(mb.ndofs(), 0.0);
682        let mut result = DVector::from_vec(std::mem::take(displacements));
683        mb.inverse_kinematics(
684            &rigidbody_set.bodies,
685            link_id,
686            options,
687            &crate::utils::transform_to_iso(&target),
688            |link| {
689                rigidbody_set
690                    .rigid_body_entity(link.rigid_body_handle())
691                    .is_some_and(&joint_can_move)
692            },
693            &mut result,
694        );
695        *displacements = result.data.into();
696        true
697    }
698}
699
700/// Wrapper around [QueryPipeline] to provide bevy friendly methods.
701///
702/// This wrapper is designed to be short lived, made whenever necessary.
703///
704/// See [RapierQueryPipeline::new_scoped] to create one.
705#[derive(Copy, Clone)]
706pub struct RapierQueryPipeline<'a> {
707    /// The query pipeline, which performs scene queries (ray-casting, point projection, etc.)
708    pub query_pipeline: QueryPipeline<'a>,
709}
710
711/// Wrapper around [QueryPipelineMut] to provide bevy friendly methods.
712///
713/// This wrapper is designed to be short lived, made whenever necessary.
714///
715/// See [RapierQueryPipelineMut::new_scoped] to create one.
716pub struct RapierQueryPipelineMut<'a> {
717    /// The query pipeline, which performs scene queries (ray-casting, point projection, etc.)
718    pub query_pipeline: QueryPipelineMut<'a>,
719}
720impl<'a> RapierQueryPipelineMut<'a> {
721    /// Creates a temporary [RapierQueryPipelineMut] and passes it as a parameter to `scoped_fn`.
722    pub fn new_scoped<T>(
723        broad_phase: &DefaultBroadPhase,
724        colliders: &mut RapierContextColliders,
725        rigid_bodies: &mut RapierRigidBodySet,
726        filter: &QueryFilter<'_>,
727        dispatcher: &dyn QueryDispatcher,
728        scoped_fn: impl FnOnce(RapierQueryPipelineMut<'_>) -> T,
729    ) -> T {
730        let predicate = to_rapier_query_filter_combined_predicate(filter);
731        let rapier_filter =
732            to_rapier_query_filter(filter, colliders, rigid_bodies, predicate.as_ref());
733        let query_pipeline = broad_phase.as_query_pipeline_mut(
734            dispatcher,
735            &mut rigid_bodies.bodies,
736            &mut colliders.colliders,
737            rapier_filter,
738        );
739        scoped_fn(RapierQueryPipelineMut { query_pipeline })
740    }
741
742    /// Downgrades the mutable reference to an immutable reference.
743    pub fn as_ref(&self) -> RapierQueryPipeline<'_> {
744        RapierQueryPipeline {
745            query_pipeline: self.query_pipeline.as_ref(),
746        }
747    }
748}
749
750/// Wraps a [bevy query filter predicate](QueryFilter::predicate) into a [rapier query filter predicate](RapierQueryFilter::predicate).
751pub fn to_rapier_query_filter_predicate(
752    predicate: &dyn Fn(Entity, &RapierCollider) -> bool,
753) -> impl Fn(ColliderHandle, &RapierCollider) -> bool + use<'_> {
754    |_: ColliderHandle, collider: &RapierCollider| -> bool {
755        let entity = RapierContextColliders::entity_from_collider(collider);
756        (predicate)(entity, collider)
757    }
758}
759
760/// Wraps the [`QueryFilter::predicate`] into a Rapier predicate, or returns `None` if it isn’t set.
761fn to_rapier_query_filter_combined_predicate<'b>(
762    filter: &QueryFilter<'b>,
763) -> Option<impl Fn(ColliderHandle, &RapierCollider) -> bool + 'b> {
764    filter.predicate.map(to_rapier_query_filter_predicate)
765}
766
767/// Converts a bevy [`QueryFilter`] into a Rapier query filter using the given Rapier predicate.
768fn to_rapier_query_filter<'b>(
769    filter: &QueryFilter<'_>,
770    colliders: &RapierContextColliders,
771    rigid_bodies: &RapierRigidBodySet,
772    predicate: Option<&'b (impl Fn(ColliderHandle, &RapierCollider) -> bool + 'b)>,
773) -> RapierQueryFilter<'b> {
774    RapierQueryFilter {
775        flags: filter.flags,
776        groups: filter.groups.map(CollisionGroups::into),
777        exclude_collider: filter
778            .exclude_collider
779            .and_then(|c| colliders.entity2collider.get(&c).copied()),
780        exclude_rigid_body: filter
781            .exclude_rigid_body
782            .and_then(|b| rigid_bodies.entity2body.get(&b).copied()),
783        predicate: predicate.map(|p| p as &dyn Fn(ColliderHandle, &RapierCollider) -> bool),
784    }
785}
786
787impl<'a> RapierQueryPipeline<'a> {
788    /// Creates a temporary [RapierQueryPipeline] and passes it as a parameter to `scoped_fn`.
789    pub fn new_scoped<T>(
790        broad_phase: &DefaultBroadPhase,
791        colliders: &RapierContextColliders,
792        rigid_bodies: &RapierRigidBodySet,
793        filter: &QueryFilter<'_>,
794        dispatcher: &dyn QueryDispatcher,
795        scoped_fn: impl FnOnce(RapierQueryPipeline<'_>) -> T,
796    ) -> T {
797        let predicate = to_rapier_query_filter_combined_predicate(filter);
798        let rapier_filter =
799            to_rapier_query_filter(filter, colliders, rigid_bodies, predicate.as_ref());
800        let query_pipeline = broad_phase.as_query_pipeline(
801            dispatcher,
802            &rigid_bodies.bodies,
803            &colliders.colliders,
804            rapier_filter,
805        );
806        scoped_fn(RapierQueryPipeline { query_pipeline })
807    }
808
809    /// Retrieves the Entity for a given collider handle.
810    pub fn collider_entity(&self, collider_handle: ColliderHandle) -> Entity {
811        RapierContextColliders::collider_entity_with_set(
812            self.query_pipeline.colliders,
813            collider_handle,
814        )
815        .unwrap()
816    }
817
818    /// Find the closest intersection between a ray and a set of collider.
819    ///
820    /// # Parameters
821    /// * `ray_origin`: the starting point of the ray to cast.
822    /// * `ray_dir`: the direction of the ray to cast.
823    /// * `max_toi`: the maximum time-of-impact that can be reported by this cast. This effectively
824    ///   limits the length of the ray to `ray.dir.norm() * max_toi`. Use `Real::MAX` for an unbounded ray.
825    /// * `solid`: if this is `true` an impact at time 0.0 (i.e. at the ray origin) is returned if
826    ///   it starts inside of a shape. If this `false` then the ray will hit the shape's boundary
827    ///   even if its starts inside of it.
828    pub fn cast_ray(
829        &self,
830        ray_origin: Vect,
831        ray_dir: Vect,
832        max_toi: Real,
833        solid: bool,
834    ) -> Option<(Entity, Real)> {
835        let ray = Ray::new(ray_origin, ray_dir);
836
837        let (h, toi) = self.query_pipeline.cast_ray(&ray, max_toi, solid)?;
838
839        Some((self.collider_entity(h), toi))
840    }
841
842    /// Find the closest intersection between a ray and a set of collider.
843    ///
844    /// # Parameters
845    /// * `ray_origin`: the starting point of the ray to cast.
846    /// * `ray_dir`: the direction of the ray to cast.
847    /// * `max_toi`: the maximum time-of-impact that can be reported by this cast. This effectively
848    ///   limits the length of the ray to `ray.dir.norm() * max_toi`. Use `Real::MAX` for an unbounded ray.
849    /// * `solid`: if this is `true` an impact at time 0.0 (i.e. at the ray origin) is returned if
850    ///   it starts inside of a shape. If this `false` then the ray will hit the shape's boundary
851    ///   even if its starts inside of it.
852    pub fn cast_ray_and_get_normal(
853        &self,
854        ray_origin: Vect,
855        ray_dir: Vect,
856        max_toi: Real,
857        solid: bool,
858    ) -> Option<(Entity, RayIntersection)> {
859        let ray = Ray::new(ray_origin, ray_dir);
860
861        let (h, result) = self
862            .query_pipeline
863            .cast_ray_and_get_normal(&ray, max_toi, solid)?;
864
865        Some((
866            self.collider_entity(h),
867            RayIntersection::from_rapier(result, ray_origin, ray_dir),
868        ))
869    }
870
871    /// Iterates through all the colliders intersecting a given ray, alongside their Rapier collider.
872    ///
873    /// # Parameters
874    /// * `ray_origin`: the starting point of the ray to cast.
875    /// * `ray_dir`: the direction of the ray to cast.
876    /// * `max_toi`: the maximum time-of-impact that can be reported by this cast. This effectively
877    ///   limits the length of the ray to `ray.dir.norm() * max_toi`. Use `Real::MAX` for an unbounded ray.
878    /// * `solid`: if this is `true` an impact at time 0.0 (i.e. at the ray origin) is returned if
879    ///   it starts inside of a shape. If this `false` then the ray will hit the shape's boundary
880    ///   even if its starts inside of it.
881    pub fn intersect_ray(
882        &'a self,
883        ray_origin: Vect,
884        ray_dir: Vect,
885        max_toi: Real,
886        solid: bool,
887    ) -> impl Iterator<Item = (Entity, &'a RapierCollider, RayIntersection)> + 'a {
888        let ray = Ray::new(ray_origin, ray_dir);
889
890        self.query_pipeline.intersect_ray(ray, max_toi, solid).map(
891            move |(_, collider, intersection)| {
892                (
893                    RapierContextColliders::entity_from_collider(collider),
894                    collider,
895                    RayIntersection::from_rapier(intersection, ray_origin, ray_dir),
896                )
897            },
898        )
899    }
900
901    /// Retrieve all the colliders intersecting the given shape, alongside their Rapier collider.
902    ///
903    /// # Parameters
904    /// * `shape_pos` - The position of the shape used for the intersection test.
905    /// * `shape_rot` - The orientation of the shape used for the intersection test.
906    /// * `shape` - The shape used for the intersection test.
907    pub fn intersect_shape(
908        &'a self,
909        shape_pos: Vect,
910        shape_rot: Rot,
911        shape: &'a (impl AsShape + ?Sized + 'a),
912    ) -> impl Iterator<Item = (Entity, &'a RapierCollider)> + 'a {
913        let shape = shape.as_shape();
914        let scaled_transform = crate::utils::pose_from(shape_pos, shape_rot);
915
916        self.query_pipeline
917            .intersect_shape(scaled_transform, shape)
918            .map(|(_, collider)| {
919                (
920                    RapierContextColliders::entity_from_collider(collider),
921                    collider,
922                )
923            })
924    }
925
926    /// Find the projection of a point on the closest collider.
927    ///
928    /// # Parameters
929    /// * `point` - The point to project.
930    /// * `max_dist` - The maximum distance between the point and its projection. Colliders
931    ///   further than this distance are ignored.
932    /// * `solid` - If this is set to `true` then the collider shapes are considered to
933    ///   be plain (if the point is located inside of a plain shape, its projection is the point
934    ///   itself). If it is set to `false` the collider shapes are considered to be hollow
935    ///   (if the point is located inside of an hollow shape, it is projected on the shape's
936    ///   boundary).
937    pub fn project_point(
938        &self,
939        point: Vect,
940        max_dist: Real,
941        solid: bool,
942    ) -> Option<(Entity, PointProjection)> {
943        let (h, result) = self.query_pipeline.project_point(point, max_dist, solid)?;
944
945        Some((
946            self.collider_entity(h),
947            PointProjection::from_rapier(result),
948        ))
949    }
950
951    /// Find all the colliders containing the given point, alongside their Rapier collider.
952    ///
953    /// # Parameters
954    /// * `point` - The point used for the containment test.
955    pub fn intersect_point(
956        &'a self,
957        point: Vect,
958    ) -> impl Iterator<Item = (Entity, &'a RapierCollider)> + 'a {
959        self.query_pipeline
960            .intersect_point(point)
961            .map(|(_, collider)| {
962                (
963                    RapierContextColliders::entity_from_collider(collider),
964                    collider,
965                )
966            })
967    }
968
969    /// Find the projection of a point on the boundary of the closest collider.
970    ///
971    /// The results include the ID of the feature hit by the point.
972    ///
973    /// # Parameters
974    /// * `point` - The point to project.
975    /// * `max_dist` - The maximum distance between the point and its projection. Colliders
976    ///   further than this distance are ignored. Use `Real::MAX` for an unbounded search.
977    pub fn project_point_and_get_feature(
978        &self,
979        point: Vect,
980        max_dist: Real,
981    ) -> Option<(Entity, PointProjection, FeatureId)> {
982        let (h, proj, fid) = self
983            .query_pipeline
984            .project_point_and_get_feature(point, max_dist)?;
985
986        Some((
987            self.collider_entity(h),
988            PointProjection::from_rapier(proj),
989            fid,
990        ))
991    }
992
993    /// Finds all the colliders with an [`Aabb`] intersecting the given [`Aabb`], alongside their
994    /// Rapier collider.
995    ///
996    /// Note that the collider AABB taken into account is the one currently stored in the query
997    /// pipeline’s BVH. It doesn’t recompute the latest collider AABB.
998    pub fn intersect_aabb_conservative(
999        &'a self,
1000        #[cfg(feature = "dim2")] aabb: bevy::shape::Aabb2d,
1001        #[cfg(feature = "dim3")] aabb: bevy::shape::Aabb3d,
1002    ) -> impl Iterator<Item = (Entity, &'a RapierCollider)> + 'a {
1003        #[cfg(feature = "dim2")]
1004        let scaled_aabb = Aabb {
1005            mins: aabb.min,
1006            maxs: aabb.max,
1007        };
1008        #[cfg(feature = "dim3")]
1009        let scaled_aabb = Aabb {
1010            mins: aabb.min.into(),
1011            maxs: aabb.max.into(),
1012        };
1013        self.query_pipeline
1014            .intersect_aabb_conservative(scaled_aabb)
1015            .map(|(_, collider)| {
1016                (
1017                    RapierContextColliders::entity_from_collider(collider),
1018                    collider,
1019                )
1020            })
1021    }
1022
1023    /// Casts a shape at a constant linear velocity and retrieve the first collider it hits.
1024    ///
1025    /// This is similar to ray-casting except that we are casting a whole shape instead of just a
1026    /// point (the ray origin). In the resulting `ShapeCastHit`, witness and normal 1 refer to the
1027    /// collider hit and are in world-space, while witness and normal 2 refer to the cast shape and
1028    /// are in its local-space (see [`ShapeCastHitDetails`](crate::geometry::ShapeCastHitDetails)).
1029    ///
1030    /// # Parameters
1031    /// * `shape_pos` - The initial translation of the shape to cast.
1032    /// * `shape_rot` - The rotation of the shape to cast.
1033    /// * `shape_vel` - The constant velocity of the shape to cast (i.e. the cast direction).
1034    /// * `shape` - The shape to cast.
1035    /// * `max_toi` - The maximum time-of-impact that can be reported by this cast. This effectively
1036    ///   limits the distance traveled by the shape to `shape_vel.norm() * maxToi`.
1037    /// * `stop_at_penetration` - If the casted shape starts in a penetration state with any
1038    ///   collider, two results are possible. If `stop_at_penetration` is `true` then, the
1039    ///   result will have a `toi` equal to `start_time`. If `stop_at_penetration` is `false`
1040    ///   then the nonlinear shape-casting will see if further motion wrt. the penetration normal
1041    ///   would result in tunnelling. If it does not (i.e. we have a separating velocity along
1042    ///   that normal) then the nonlinear shape-casting will attempt to find another impact,
1043    ///   at a time `> start_time` that could result in tunnelling.
1044    #[allow(clippy::too_many_arguments)]
1045    pub fn cast_shape(
1046        &'a self,
1047        shape_pos: Vect,
1048        shape_rot: Rot,
1049        shape_vel: Vect,
1050        shape: &(impl AsShape + ?Sized),
1051        options: ShapeCastOptions,
1052    ) -> Option<(Entity, ShapeCastHit)> {
1053        let shape = shape.as_shape();
1054        let scaled_transform = crate::utils::pose_from(shape_pos, shape_rot);
1055
1056        let (h, result) =
1057            self.query_pipeline
1058                .cast_shape(&scaled_transform, shape_vel, shape, options)?;
1059
1060        Some((
1061            self.collider_entity(h),
1062            ShapeCastHit::from_rapier(result, options.compute_impact_geometry_on_penetration),
1063        ))
1064    }
1065
1066    /// Casts a shape with an arbitrary continuous motion and retrieve the first collider it hits.
1067    ///
1068    /// In the resulting `ShapeCastHit`, witness and normal 1 refer to the collider hit and are in
1069    /// world-space, while witness and normal 2 refer to the cast shape and are in its local-space.
1070    ///
1071    /// # Parameters
1072    /// * `shape_motion` - The motion of the shape.
1073    /// * `shape` - The shape to cast.
1074    /// * `start_time` - The starting time of the interval where the motion takes place.
1075    /// * `end_time` - The end time of the interval where the motion takes place.
1076    /// * `stop_at_penetration` - If the casted shape starts in a penetration state with any
1077    ///   collider, two results are possible. If `stop_at_penetration` is `true` then, the
1078    ///   result will have a `toi` equal to `start_time`. If `stop_at_penetration` is `false`
1079    ///   then the nonlinear shape-casting will see if further motion wrt. the penetration normal
1080    ///   would result in tunnelling. If it does not (i.e. we have a separating velocity along
1081    ///   that normal) then the nonlinear shape-casting will attempt to find another impact,
1082    ///   at a time `> start_time` that could result in tunnelling.
1083    pub fn cast_shape_nonlinear(
1084        &self,
1085        shape_motion: &NonlinearMotion,
1086        shape: &(impl AsShape + ?Sized),
1087        start_time: Real,
1088        end_time: Real,
1089        stop_at_penetration: bool,
1090    ) -> Option<(Entity, ShapeCastHit)> {
1091        let shape = shape.as_shape();
1092        let (h, result) = self.query_pipeline.cast_shape_nonlinear(
1093            &shape_motion.into_rapier(),
1094            shape,
1095            start_time,
1096            end_time,
1097            stop_at_penetration,
1098        )?;
1099
1100        Some((
1101            self.collider_entity(h),
1102            ShapeCastHit::from_rapier(result, false),
1103        ))
1104    }
1105
1106    /// Computes the smallest distance between the given shape and the closest collider.
1107    ///
1108    /// Returns the entity of the closest collider alongside that distance, which is `0.0` if they
1109    /// are intersecting. Returns `None` if no collider passes the query filter.
1110    ///
1111    /// # Parameters
1112    /// * `shape_pos` - The translation of the shape.
1113    /// * `shape_rot` - The rotation of the shape.
1114    /// * `shape` - The shape to compute the distance from.
1115    pub fn distance_to_shape(
1116        &self,
1117        shape_pos: Vect,
1118        shape_rot: Rot,
1119        shape: &(impl AsShape + ?Sized),
1120    ) -> Option<(Entity, Real)> {
1121        let shape = shape.as_shape();
1122        let pose = crate::utils::pose_from(shape_pos, shape_rot);
1123        let (id, dist) = CompositeShapeRef(&self.query_pipeline).distance_to_shape(
1124            self.query_pipeline.dispatcher,
1125            &pose,
1126            shape,
1127        )?;
1128        Some((self.collider_entity_from_id(id)?, dist.distance))
1129    }
1130
1131    /// Computes the closest points between the given shape and the closest collider.
1132    ///
1133    /// Returns the entity of the closest collider alongside the closest points. In
1134    /// [`ShapeClosestPoints::WithinMargin`], the first point is on the collider and the second
1135    /// point is on `shape`, both in world-space. Returns `None` if no collider lies within
1136    /// `max_dist` of `shape`.
1137    ///
1138    /// # Parameters
1139    /// * `shape_pos` - The translation of the shape.
1140    /// * `shape_rot` - The rotation of the shape.
1141    /// * `shape` - The shape to compute the closest points from.
1142    /// * `max_dist` - Colliders further than this distance from `shape` are ignored.
1143    pub fn closest_points_to_shape(
1144        &self,
1145        shape_pos: Vect,
1146        shape_rot: Rot,
1147        shape: &(impl AsShape + ?Sized),
1148        max_dist: Real,
1149    ) -> Option<(Entity, ShapeClosestPoints)> {
1150        let shape = shape.as_shape();
1151        let pose = crate::utils::pose_from(shape_pos, shape_rot);
1152        let (id, mut pts) = CompositeShapeRef(&self.query_pipeline).closest_points_to_shape(
1153            self.query_pipeline.dispatcher,
1154            &pose,
1155            shape,
1156            max_dist,
1157        )?;
1158        match &mut pts {
1159            ClosestPoints::Disjoint => return None,
1160            ClosestPoints::Intersecting => {}
1161            // The first point is already in world-space, the second one is local to `shape`.
1162            ClosestPoints::WithinMargin(_, p2) => *p2 = pose * *p2,
1163        }
1164        Some((
1165            self.collider_entity_from_id(id)?,
1166            ShapeClosestPoints::from_rapier(pts),
1167        ))
1168    }
1169
1170    /// Computes the contact between the given shape and the closest (or deepest penetrating)
1171    /// collider.
1172    ///
1173    /// Returns the entity of that collider alongside the contact, where the first shape is the
1174    /// collider and the second shape is `shape`; contact points and normals are in world-space.
1175    /// Returns `None` if no collider lies within `prediction` of `shape`.
1176    ///
1177    /// # Parameters
1178    /// * `shape_pos` - The translation of the shape.
1179    /// * `shape_rot` - The rotation of the shape.
1180    /// * `shape` - The shape to compute the contact with.
1181    /// * `prediction` - Colliders further than this distance from `shape` are ignored.
1182    pub fn contact_with_shape(
1183        &self,
1184        shape_pos: Vect,
1185        shape_rot: Rot,
1186        shape: &(impl AsShape + ?Sized),
1187        prediction: Real,
1188    ) -> Option<(Entity, ShapeContact)> {
1189        let shape = shape.as_shape();
1190        let pose = crate::utils::pose_from(shape_pos, shape_rot);
1191        let (id, mut contact) = CompositeShapeRef(&self.query_pipeline).contact_with_shape(
1192            self.query_pipeline.dispatcher,
1193            &pose,
1194            shape,
1195            prediction,
1196        )?;
1197        // The first point and normal are already in world-space, the second ones are local to `shape`.
1198        contact.point2 = pose * contact.point2;
1199        contact.normal2 = pose.rotation * contact.normal2;
1200        Some((
1201            self.collider_entity_from_id(id)?,
1202            ShapeContact::from_rapier(contact),
1203        ))
1204    }
1205
1206    /// The bounding volume hierarchy containing the world-space AABB of every collider.
1207    ///
1208    /// This can be used for custom scene traversals. Each leaf index identifies a collider and
1209    /// can be resolved with [`Self::bvh_leaf_collider`]. Note that the BVH itself ignores the
1210    /// query filter.
1211    pub fn bvh(&self) -> &'a Bvh {
1212        self.query_pipeline.bvh
1213    }
1214
1215    /// Retrieves the entity and Rapier collider identified by a leaf index of [`Self::bvh`].
1216    ///
1217    /// Returns `None` if the collider doesn't exist or is rejected by the query filter.
1218    pub fn bvh_leaf_collider(&self, leaf: u32) -> Option<(Entity, &'a RapierCollider)> {
1219        let (collider, handle) = self.query_pipeline.colliders.get_unknown_gen(leaf)?;
1220        self.query_pipeline
1221            .filter
1222            .test(self.query_pipeline.bodies, handle, collider)
1223            .then(|| {
1224                (
1225                    RapierContextColliders::entity_from_collider(collider),
1226                    collider,
1227                )
1228            })
1229    }
1230
1231    /// Retrieves the Entity of the collider identified by a sub-shape id of the query pipeline.
1232    fn collider_entity_from_id(&self, id: u32) -> Option<Entity> {
1233        self.query_pipeline
1234            .colliders
1235            .get_unknown_gen(id)
1236            .map(|(collider, _)| RapierContextColliders::entity_from_collider(collider))
1237    }
1238}
1239
1240/// The set of rigid-bodies part of the simulation.
1241///
1242/// This should be attached on an entity with a [`RapierContextSimulation`]
1243///
1244/// With the `serde-serialize` feature, the entity-to-handle map isn't serialized: it is rebuilt
1245/// from the rigid-bodies’ user-data on deserialization (see [`Self::rebuild_entity_maps`]).
1246#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
1247#[cfg_attr(
1248    feature = "serde-serialize",
1249    serde(from = "serde_shadows::RapierRigidBodySetData")
1250)]
1251#[derive(Component, Default, Clone)]
1252pub struct RapierRigidBodySet {
1253    /// The set of rigid-bodies part of the simulation.
1254    pub bodies: RigidBodySet,
1255    /// The set of soft-bodies part of the simulation.
1256    pub soft_bodies: SoftBodySet,
1257    /// NOTE: this map is needed to handle despawning.
1258    #[cfg_attr(feature = "serde-serialize", serde(skip))]
1259    pub(crate) entity2body: HashMap<Entity, RigidBodyHandle>,
1260    /// NOTE: this map is needed to handle despawning.
1261    #[cfg_attr(feature = "serde-serialize", serde(skip))]
1262    pub(crate) entity2soft_body: HashMap<Entity, SoftBodyHandle>,
1263
1264    /// For transform change detection.
1265    #[cfg_attr(feature = "serde-serialize", serde(skip))]
1266    pub(crate) last_body_transform_set: HashMap<RigidBodyHandle, GlobalTransform>,
1267}
1268
1269impl RapierRigidBodySet {
1270    /// Rebuilds the map from entities to rigid-body handles from the user-data of the
1271    /// rigid-bodies, which contain the bits of their entity.
1272    ///
1273    /// This is called automatically when deserializing this component. Call it manually after
1274    /// replacing [`Self::bodies`] with a set restored in another way. The transform change
1275    /// detection state is reset, so the next [`GlobalTransform`] change of a rigid-body entity
1276    /// is applied to its rigid-body.
1277    ///
1278    /// The soft-body map is rebuilt from the soft bodies' user-data too. The hidden proxy
1279    /// rigid-bodies of the soft bodies are not mapped, except the proxies of the clusters that
1280    /// have their own entity (see [`SoftBodyCluster`](crate::dynamics::SoftBodyCluster)) and the
1281    /// whole-body proxy of each soft body (see [`Self::soft_body_whole_proxy`]).
1282    pub fn rebuild_entity_maps(&mut self) {
1283        let soft_bodies = &self.soft_bodies;
1284        self.entity2body = self
1285            .bodies
1286            .iter()
1287            .filter(|(_, rb)| {
1288                // A proxy with the user-data of its soft body stands for the soft body entity.
1289                rb.soft_body()
1290                    .and_then(|h| soft_bodies.get(h))
1291                    .is_none_or(|sb| sb.user_data != rb.user_data)
1292            })
1293            .filter_map(|(handle, rb)| Some((Entity::try_from_bits(rb.user_data as u64)?, handle)))
1294            .collect();
1295        self.entity2soft_body = self
1296            .soft_bodies
1297            .iter()
1298            .filter_map(|(handle, sb)| Some((Entity::try_from_bits(sb.user_data as u64)?, handle)))
1299            .collect();
1300        let soft_bodies: Vec<_> = self
1301            .entity2soft_body
1302            .iter()
1303            .map(|(entity, handle)| (*entity, *handle))
1304            .collect();
1305        for (entity, handle) in soft_bodies {
1306            self.map_soft_body_whole_proxy(entity, handle);
1307        }
1308        self.last_body_transform_set.clear();
1309    }
1310
1311    /// Maps `entity` to the whole-body proxy of its soft body `handle` (or unmaps it if the soft
1312    /// body has none).
1313    pub(crate) fn map_soft_body_whole_proxy(&mut self, entity: Entity, handle: SoftBodyHandle) {
1314        match self.whole_proxy(entity, handle) {
1315            Some(proxy) => {
1316                self.entity2body.insert(entity, proxy);
1317            }
1318            None => {
1319                self.entity2body.remove(&entity);
1320            }
1321        }
1322    }
1323
1324    /// The whole-body proxy of the soft body `handle` standing for `entity`: its root body, or
1325    /// else the proxy of a cluster covering all its particles.
1326    fn whole_proxy(&self, entity: Entity, handle: SoftBodyHandle) -> Option<RigidBodyHandle> {
1327        let sb = self.soft_bodies.get(handle)?;
1328        let bits = entity.to_bits() as u128;
1329        let stands_for_entity = |proxy: RigidBodyHandle| {
1330            self.bodies
1331                .get(proxy)
1332                .is_some_and(|rb| rb.user_data == bits)
1333        };
1334        let root = sb.root_body();
1335        if stands_for_entity(root) {
1336            return Some(root);
1337        }
1338        sb.live_clusters()
1339            .map(|(_, cluster)| cluster)
1340            .find(|cluster| {
1341                cluster.particles().len() == sb.num_particles()
1342                    && stands_for_entity(cluster.proxy())
1343            })
1344            .map(|cluster| cluster.proxy())
1345    }
1346
1347    /// Moves the Rapier objects of the new soft body `handle` (split off another one by a tear) to
1348    /// `entity`: the user-data of the soft body and of its proxies and colliders standing for the
1349    /// soft body it was split from.
1350    pub(crate) fn map_soft_body_piece(
1351        &mut self,
1352        colliders: &mut RapierContextColliders,
1353        handle: SoftBodyHandle,
1354        entity: Entity,
1355    ) {
1356        let new_bits = entity.to_bits() as u128;
1357        let Some(sb) = self.soft_bodies.get_mut(handle) else {
1358            return;
1359        };
1360        let old_bits = sb.user_data;
1361        sb.user_data = new_bits;
1362        for (_, cluster) in sb.live_clusters() {
1363            let Some(rb) = self.bodies.get_mut(cluster.proxy()) else {
1364                continue;
1365            };
1366            if rb.user_data == old_bits {
1367                rb.user_data = new_bits;
1368            }
1369            for co_handle in rb.colliders() {
1370                if let Some(co) = colliders.colliders.get_mut(*co_handle) {
1371                    if co.user_data == old_bits {
1372                        co.user_data = new_bits;
1373                    }
1374                }
1375            }
1376        }
1377        self.entity2soft_body.insert(entity, handle);
1378    }
1379
1380    /// Maps the soft body entity to the collider of the soft body's collision mesh.
1381    pub(crate) fn map_soft_body_collision_mesh(
1382        &self,
1383        colliders: &mut RapierContextColliders,
1384        handle: SoftBodyHandle,
1385        entity: Entity,
1386    ) {
1387        match self
1388            .soft_bodies
1389            .get(handle)
1390            .and_then(|sb| sb.collision_mesh())
1391        {
1392            Some(mesh) => {
1393                colliders.entity2collider.insert(entity, mesh.collider());
1394            }
1395            None => {
1396                colliders.entity2collider.remove(&entity);
1397            }
1398        }
1399    }
1400
1401    /// The colliders standing for the soft body of `entity`: the colliders of its collision
1402    /// meshes (or of its particles), attached to its proxies and reporting `entity` as their
1403    /// entity. The colliders attached by the user to its proxies (e.g. [`DeformableCollider`]s or
1404    /// children colliders) are not included.
1405    ///
1406    /// Returns `None` if `entity` has no soft body.
1407    ///
1408    /// [`DeformableCollider`]: crate::dynamics::DeformableCollider
1409    pub fn soft_body_colliders(
1410        &self,
1411        colliders: &ColliderSet,
1412        entity: Entity,
1413    ) -> Option<Vec<ColliderHandle>> {
1414        let sb = self.soft_body(entity)?;
1415        let bits = entity.to_bits() as u128;
1416        let mut result = vec![];
1417        for (_, cluster) in sb.live_clusters() {
1418            let Some(rb) = self.bodies.get(cluster.proxy()) else {
1419                continue;
1420            };
1421            result.extend(
1422                rb.colliders()
1423                    .iter()
1424                    .copied()
1425                    .filter(|h| colliders.get(*h).is_some_and(|co| co.user_data == bits)),
1426            );
1427        }
1428        Some(result)
1429    }
1430
1431    /// The map from entities to soft-body handles.
1432    pub fn entity2soft_body(&self) -> &HashMap<Entity, SoftBodyHandle> {
1433        &self.entity2soft_body
1434    }
1435
1436    /// Retrieve the Bevy entity of the given Rapier soft body (identified by its handle).
1437    pub fn soft_body_entity(&self, handle: SoftBodyHandle) -> Option<Entity> {
1438        let entity = Entity::try_from_bits(self.soft_bodies.get(handle)?.user_data as u64)?;
1439        (self.entity2soft_body.get(&entity) == Some(&handle)).then_some(entity)
1440    }
1441
1442    /// The Rapier soft body attached to the given `entity`, if any.
1443    pub fn soft_body(&self, entity: Entity) -> Option<&RapierSoftBody> {
1444        self.soft_bodies.get(*self.entity2soft_body.get(&entity)?)
1445    }
1446
1447    /// The Rapier soft body attached to the given `entity`, if any.
1448    ///
1449    /// This gives access to every setter of the soft body (particle positions, velocities and
1450    /// kinematic targets, pinning, forces, impulses, clusters...). Prefer the soft-body components
1451    /// (e.g. [`SoftBodyMaterial`](crate::dynamics::SoftBodyMaterial)) for the properties they
1452    /// cover, since they are applied again whenever they change.
1453    pub fn soft_body_mut(&mut self, entity: Entity) -> Option<&mut RapierSoftBody> {
1454        self.soft_bodies
1455            .get_mut(*self.entity2soft_body.get(&entity)?)
1456    }
1457
1458    /// The world-space positions of the particles of the soft body of `entity`.
1459    ///
1460    /// Returns `None` if `entity` has no soft body.
1461    pub fn soft_body_particle_positions(
1462        &self,
1463        entity: Entity,
1464    ) -> Option<impl ExactSizeIterator<Item = Vect> + '_> {
1465        Some(self.soft_body(entity)?.particle_positions())
1466    }
1467
1468    /// The world-space velocities of the particles of the soft body of `entity`.
1469    ///
1470    /// Returns `None` if `entity` has no soft body.
1471    pub fn soft_body_particle_velocities(
1472        &self,
1473        entity: Entity,
1474    ) -> Option<impl ExactSizeIterator<Item = Vect> + '_> {
1475        Some(self.soft_body(entity)?.particle_velocities())
1476    }
1477
1478    /// The area (2D) or volume (3D) currently enclosed by the soft body of `entity` (`0.0` for a
1479    /// soft body without closed boundary).
1480    ///
1481    /// Returns `None` if `entity` has no soft body.
1482    pub fn soft_body_volume(&self, entity: Entity) -> Option<Real> {
1483        Some(self.soft_body(entity)?.volume())
1484    }
1485
1486    /// The total mass of the particles of the soft body of `entity`.
1487    ///
1488    /// Returns `None` if `entity` has no soft body.
1489    pub fn soft_body_mass(&self, entity: Entity) -> Option<Real> {
1490        Some(self.soft_body(entity)?.mass())
1491    }
1492
1493    /// The world-space, mass-weighted, center of the particles of the soft body of `entity`.
1494    ///
1495    /// Returns `None` if `entity` has no soft body.
1496    pub fn soft_body_center_of_mass(&self, entity: Entity) -> Option<Vect> {
1497        Some(self.soft_body(entity)?.center_of_mass())
1498    }
1499
1500    /// Whether the soft body of `entity` is sleeping.
1501    ///
1502    /// Returns `None` if `entity` has no soft body.
1503    pub fn is_soft_body_sleeping(&self, entity: Entity) -> Option<bool> {
1504        Some(self.soft_body(entity)?.is_sleeping())
1505    }
1506
1507    /// Wakes up the soft body of `entity` (effective at the start of the next step, together
1508    /// with the island of the bodies it touches).
1509    ///
1510    /// Returns `false` if `entity` has no soft body.
1511    pub fn wake_up_soft_body(&mut self, entity: Entity, strong: bool) -> bool {
1512        let Some(handle) = self.entity2soft_body.get(&entity).copied() else {
1513            return false;
1514        };
1515        self.soft_bodies.wake_up(handle, &mut self.bodies, strong);
1516        true
1517    }
1518
1519    /// The proxy rigid-body of the cluster `cluster` of the soft body of `entity`.
1520    ///
1521    /// The cluster `0` is the whole-body cluster created with the soft body. Returns `None` if
1522    /// `entity` has no soft body or if that cluster doesn't exist.
1523    pub fn soft_body_cluster_proxy(&self, entity: Entity, cluster: u32) -> Option<RigidBodyHandle> {
1524        self.soft_body(entity)?.cluster_proxy(cluster)
1525    }
1526
1527    /// The whole-body proxy rigid-body of the soft body of `entity`: the proxy of its cluster
1528    /// covering all its particles, which `entity` is mapped to in [`Self::entity2body`].
1529    ///
1530    /// This lets the soft body entity be used like a rigid-body entity by impulse joints (as
1531    /// their `parent`, or on the soft body entity itself). Returns `None` if `entity` has no soft
1532    /// body.
1533    pub fn soft_body_whole_proxy(&self, entity: Entity) -> Option<RigidBodyHandle> {
1534        self.whole_proxy(entity, *self.entity2soft_body.get(&entity)?)
1535    }
1536
1537    /// The soft body and the index of the cluster standing for `entity`: a
1538    /// [`SoftBodyCluster`](crate::dynamics::SoftBodyCluster) entity, or a soft body entity (for
1539    /// its whole-body cluster).
1540    ///
1541    /// The index can be given to the cluster methods of [`RapierSoftBody`] (e.g.
1542    /// [`RapierSoftBody::set_cluster_pinned`]). It may change when the soft body tears, so it
1543    /// should not be stored. Returns `None` if `entity` doesn't stand for a live cluster.
1544    pub fn soft_body_cluster_index(&self, entity: Entity) -> Option<(SoftBodyHandle, u32)> {
1545        let proxy = *self.entity2body.get(&entity)?;
1546        let handle = self.bodies.get(proxy)?.soft_body()?;
1547        let sb = self.soft_bodies.get(handle)?;
1548        let index = self
1549            .bodies
1550            .get(proxy)?
1551            .soft_cluster()
1552            .filter(|i| sb.cluster_proxy(*i) == Some(proxy))
1553            .or_else(|| {
1554                sb.live_clusters()
1555                    .find(|(_, cluster)| cluster.proxy() == proxy)
1556                    .map(|(i, _)| i)
1557            })?;
1558        Some((handle, index))
1559    }
1560
1561    /// The map from entities to rigid-body handles.
1562    pub fn entity2body(&self) -> &HashMap<Entity, RigidBodyHandle> {
1563        &self.entity2body
1564    }
1565
1566    /// Retrieve the Bevy entity the given Rapier rigid-body (identified by its handle) is attached.
1567    pub fn rigid_body_entity(&self, handle: RigidBodyHandle) -> Option<Entity> {
1568        self.bodies
1569            .get(handle)
1570            .map(|c| Entity::from_bits(c.user_data as u64))
1571    }
1572
1573    /// This method makes sure that the rigid-body positions have been propagated to
1574    /// their attached colliders, without having to perform a simulation step.
1575    pub fn propagate_modified_body_positions_to_colliders(
1576        &self,
1577        colliders: &mut RapierContextColliders,
1578    ) {
1579        self.bodies
1580            .propagate_modified_body_positions_to_colliders(&mut colliders.colliders);
1581    }
1582
1583    /// Computes the angle between the two bodies attached by the [`RevoluteJoint`] component (if any) referenced by the given `entity`.
1584    ///
1585    /// The angle is computed along the revolute joint’s principal axis.
1586    ///
1587    /// Parameter `entity` should have a [`ImpulseJoint`] component with a [`TypedJoint::RevoluteJoint`] variant as `data`.
1588    pub fn impulse_revolute_joint_angle(
1589        &self,
1590        joints: &RapierContextJoints,
1591        entity: Entity,
1592    ) -> Option<f32> {
1593        let joint_handle = joints.entity2impulse_joint().get(&entity)?;
1594        let impulse_joint = joints.impulse_joints.get(*joint_handle)?;
1595        let revolute_joint = impulse_joint.data.as_revolute()?;
1596
1597        let rb1 = &self.bodies[impulse_joint.body1()];
1598        let rb2 = &self.bodies[impulse_joint.body2()];
1599        Some(revolute_joint.angle(rb1.rotation(), rb2.rotation()))
1600    }
1601
1602    /// The Rapier rigid-body attached to the given `entity`, if any.
1603    fn body(&self, entity: Entity) -> Option<&rapier::dynamics::RigidBody> {
1604        self.bodies.get(*self.entity2body.get(&entity)?)
1605    }
1606
1607    /// The linear velocity of the given world-space `point`, assuming it is rigidly attached to the
1608    /// rigid-body of `entity`.
1609    ///
1610    /// Unlike [`crate::dynamics::Velocity::linear_velocity_at_point`], this uses the center of mass
1611    /// computed by Rapier. Returns `None` if `entity` has no rigid-body.
1612    pub fn velocity_at_point(&self, entity: Entity, point: Vect) -> Option<Vect> {
1613        Some(self.body(entity)?.velocity_at_point(point))
1614    }
1615
1616    /// Returns `true` if the rigid-body of `entity` has a non-zero linear or angular velocity.
1617    ///
1618    /// Returns `None` if `entity` has no rigid-body.
1619    pub fn is_moving(&self, entity: Entity) -> Option<bool> {
1620        Some(self.body(entity)?.is_moving())
1621    }
1622
1623    /// Returns `true` if CCD is active for the rigid-body of `entity`, i.e., if it moved fast
1624    /// enough during the last step to justify a CCD run.
1625    ///
1626    /// Returns `None` if `entity` has no rigid-body.
1627    pub fn is_ccd_active(&self, entity: Entity) -> Option<bool> {
1628        Some(self.body(entity)?.is_ccd_active())
1629    }
1630
1631    /// The next position of the rigid-body of `entity`.
1632    ///
1633    /// For kinematic rigid-bodies, this is the position set by the user for the next step. For
1634    /// other rigid-bodies, this value is currently unspecified. The returned transform has a unit
1635    /// scale. Returns `None` if `entity` has no rigid-body.
1636    pub fn next_position(&self, entity: Entity) -> Option<Transform> {
1637        Some(crate::utils::iso_to_transform(
1638            self.body(entity)?.next_position(),
1639        ))
1640    }
1641
1642    /// Predicts the position of the rigid-body of `entity` after `dt` seconds, by integrating its
1643    /// current velocity and forces (including gravity).
1644    ///
1645    /// The returned transform has a unit scale. Returns `None` if `entity` has no rigid-body.
1646    pub fn predict_position_using_velocity_and_forces(
1647        &self,
1648        entity: Entity,
1649        dt: Real,
1650    ) -> Option<Transform> {
1651        Some(crate::utils::iso_to_transform(
1652            &self
1653                .body(entity)?
1654                .predict_position_using_velocity_and_forces(dt),
1655        ))
1656    }
1657
1658    /// Predicts the position of the rigid-body of `entity` after `dt` seconds, by integrating its
1659    /// current velocity only (forces are ignored).
1660    ///
1661    /// The returned transform has a unit scale. Returns `None` if `entity` has no rigid-body.
1662    pub fn predict_position_using_velocity(&self, entity: Entity, dt: Real) -> Option<Transform> {
1663        Some(crate::utils::iso_to_transform(
1664            &self.body(entity)?.predict_position_using_velocity(dt),
1665        ))
1666    }
1667
1668    /// The kinetic energy of the rigid-body of `entity`.
1669    ///
1670    /// Returns `None` if `entity` has no rigid-body.
1671    pub fn kinetic_energy(&self, entity: Entity) -> Option<Real> {
1672        Some(self.body(entity)?.kinetic_energy())
1673    }
1674
1675    /// The gravitational potential energy of the rigid-body of `entity`.
1676    ///
1677    /// The position is projected back by half a timestep `dt` so the result is synchronized with
1678    /// [`Self::kinetic_energy`]. Returns `None` if `entity` has no rigid-body.
1679    pub fn gravitational_potential_energy(
1680        &self,
1681        entity: Entity,
1682        dt: Real,
1683        gravity: Vect,
1684    ) -> Option<Real> {
1685        Some(
1686            self.body(entity)?
1687                .gravitational_potential_energy(dt, gravity),
1688        )
1689    }
1690
1691    /// The total user force applied to the rigid-body of `entity` (e.g. from its
1692    /// [`crate::dynamics::ExternalForce`] component).
1693    ///
1694    /// This is zero for non-dynamic rigid-bodies. Returns `None` if `entity` has no rigid-body.
1695    pub fn user_force(&self, entity: Entity) -> Option<Vect> {
1696        Some(self.body(entity)?.user_force())
1697    }
1698
1699    /// The total user torque applied to the rigid-body of `entity` (e.g. from its
1700    /// [`crate::dynamics::ExternalForce`] component).
1701    ///
1702    /// This is zero for non-dynamic rigid-bodies. Returns `None` if `entity` has no rigid-body.
1703    #[cfg(feature = "dim2")]
1704    pub fn user_torque(&self, entity: Entity) -> Option<Real> {
1705        Some(self.body(entity)?.user_torque())
1706    }
1707
1708    /// The total user torque applied to the rigid-body of `entity` (e.g. from its
1709    /// [`crate::dynamics::ExternalForce`] component).
1710    ///
1711    /// This is zero for non-dynamic rigid-bodies. Returns `None` if `entity` has no rigid-body.
1712    #[cfg(feature = "dim3")]
1713    pub fn user_torque(&self, entity: Entity) -> Option<Vect> {
1714        Some(self.body(entity)?.user_torque())
1715    }
1716
1717    /// The dominance group actually used by the solver for the rigid-body of `entity`.
1718    ///
1719    /// This is `i8::MAX + 1` for non-dynamic rigid-bodies. Returns `None` if `entity` has no
1720    /// rigid-body.
1721    pub fn effective_dominance_group(&self, entity: Entity) -> Option<i16> {
1722        Some(self.body(entity)?.effective_dominance_group())
1723    }
1724
1725    /// The world-space center of mass of the rigid-body of `entity`.
1726    ///
1727    /// Returns `None` if `entity` has no rigid-body.
1728    pub fn center_of_mass(&self, entity: Entity) -> Option<Vect> {
1729        Some(self.body(entity)?.center_of_mass())
1730    }
1731
1732    /// The mass of the rigid-body of `entity` (including the contributions of its colliders).
1733    ///
1734    /// This is zero for rigid-bodies without mass. Returns `None` if `entity` has no rigid-body.
1735    pub fn mass(&self, entity: Entity) -> Option<Real> {
1736        Some(self.body(entity)?.mass())
1737    }
1738}
1739
1740/// Teleports the kinematic position-based rigid-bodies to their next kinematic position.
1741///
1742/// This emulates, in collision-only mode, the motion the physics pipeline would apply.
1743fn apply_kinematic_targets(bodies: &mut RigidBodySet) {
1744    let targets: Vec<_> = bodies
1745        .iter()
1746        .filter(|(_, rb)| {
1747            rb.body_type() == RigidBodyType::KinematicPositionBased
1748                && rb.position() != rb.next_position()
1749        })
1750        .map(|(handle, rb)| (handle, *rb.next_position()))
1751        .collect();
1752    for (handle, pose) in targets {
1753        if let Some(rb) = bodies.get_mut(handle) {
1754            rb.set_position(pose, false);
1755        }
1756    }
1757}
1758
1759/// A soft-body tear waiting for the `handle_soft_body_tears` system.
1760pub(crate) struct PendingSoftBodyTear {
1761    /// The Rapier tear event.
1762    pub raw: RapierSoftBodyTearEvent,
1763    /// The entities already spawned for the pieces split off the torn body (the pieces of `raw`
1764    /// but the first), or empty if they must be spawned by the system.
1765    pub piece_entities: Vec<Entity>,
1766}
1767
1768/// Statistics about the simulation steps executed by the last call to
1769/// [`RapierContextSimulation::step_simulation`], i.e., during the last physics update.
1770///
1771/// The step count and time are measured by `bevy_rapier` and always available. The other
1772/// statistics are read from the [`PhysicsPipeline::counters`] after each step, and are only
1773/// measured while these counters are enabled (e.g. by the
1774/// [`RapierDiagnosticsPlugin`](crate::plugin::diagnostics::RapierDiagnosticsPlugin)). The other
1775/// timings also require the `profiler` feature. In [`SimulationMode::CollisionOnly`], only the
1776/// contact pairs are counted besides the steps.
1777#[derive(Copy, Clone, Debug, Default, PartialEq)]
1778pub struct SimulationStepStats {
1779    /// The number of simulation steps (including substeps) executed.
1780    pub num_steps: usize,
1781    /// The total wall-clock time spent running the simulation steps, in milliseconds.
1782    pub step_time_ms: f64,
1783    /// Time spent on collision detection (broad-phase and narrow-phase), in milliseconds.
1784    pub collision_detection_time_ms: f64,
1785    /// Time spent in the broad-phase, in milliseconds.
1786    pub broad_phase_time_ms: f64,
1787    /// Time spent in the narrow-phase, in milliseconds.
1788    pub narrow_phase_time_ms: f64,
1789    /// Time spent building the simulation islands, in milliseconds.
1790    pub island_construction_time_ms: f64,
1791    /// Time spent in the constraints solver, in milliseconds.
1792    pub solver_time_ms: f64,
1793    /// Time spent on Continuous Collision Detection, in milliseconds.
1794    pub ccd_time_ms: f64,
1795    /// Time spent updating the rigid-bodies’ positions and velocities, in milliseconds.
1796    pub update_time_ms: f64,
1797    /// The number of CCD substeps executed (zero on the steps where the CCD didn't need to act).
1798    pub ccd_substeps: usize,
1799    /// The number of contact pairs tracked by the narrow-phase (touching or not) after the last
1800    /// step.
1801    pub num_contact_pairs: usize,
1802    /// The number of contact manifolds and impulse joints handed to the constraints solver,
1803    /// summed over the steps. The contacts and joints of sleeping bodies aren't counted.
1804    pub num_solver_constraints: usize,
1805    /// The number of contact points handed to the constraints solver, soft-body contacts
1806    /// included, summed over the steps.
1807    pub num_solver_contacts: usize,
1808}
1809
1810impl SimulationStepStats {
1811    /// Adds the counters of the last step of `pipeline` to these statistics.
1812    fn accumulate_counters(&mut self, pipeline: &PhysicsPipeline) {
1813        let counters = &pipeline.counters;
1814        self.collision_detection_time_ms += counters.collision_detection_time_ms();
1815        self.broad_phase_time_ms += counters.broad_phase_time_ms();
1816        self.narrow_phase_time_ms += counters.narrow_phase_time_ms();
1817        self.island_construction_time_ms += counters.island_construction_time_ms();
1818        self.solver_time_ms += counters.solver_time_ms();
1819        self.ccd_time_ms += counters.ccd_time_ms();
1820        self.update_time_ms += counters.update_time_ms();
1821        self.ccd_substeps += counters.ccd.num_substeps;
1822        self.num_contact_pairs = counters.cd.ncontact_pairs;
1823        self.num_solver_constraints += counters.solver.nconstraints;
1824        self.num_solver_contacts += counters.solver.ncontacts;
1825    }
1826}
1827
1828/// The Rapier context, containing parts of the state of the physics engine, specific to the simulation step.
1829///
1830/// This is the main driver for a rapier context, which will create other required components if needed.
1831///
1832/// Additionally to its required components, this component is also always paired with a [`RapierConfiguration`][crate::prelude::RapierConfiguration] component.
1833#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
1834#[derive(Component)]
1835#[require(
1836    RapierContextColliders,
1837    RapierRigidBodySet,
1838    RapierContextJoints,
1839    SimulationToRenderTime
1840)]
1841pub struct RapierContextSimulation {
1842    /// The island manager, which detects what object is sleeping
1843    /// (not moving much) to reduce computations.
1844    pub islands: IslandManager,
1845    /// The broad-phase, which detects potential contact pairs.
1846    pub broad_phase: DefaultBroadPhase,
1847    /// The narrow-phase, which computes contact points, tests intersections,
1848    /// and maintain the contact and intersection graphs.
1849    pub narrow_phase: NarrowPhase,
1850    /// The solver, which handles Continuous Collision Detection (CCD).
1851    pub ccd_solver: CCDSolver,
1852    /// The physics pipeline, which advance the simulation step by step.
1853    #[cfg_attr(feature = "serde-serialize", serde(skip))]
1854    pub pipeline: PhysicsPipeline,
1855    /// The collision pipeline, which only runs collision detection when the context is in
1856    /// [`SimulationMode::CollisionOnly`].
1857    #[cfg_attr(feature = "serde-serialize", serde(skip))]
1858    pub collision_pipeline: CollisionPipeline,
1859    /// The integration parameters, controlling various low-level coefficient of the simulation.
1860    pub integration_parameters: IntegrationParameters,
1861    /// The user-provided event handler, see [`Self::set_event_handler`].
1862    #[cfg_attr(feature = "serde-serialize", serde(skip))]
1863    pub(crate) event_handler: Option<Box<dyn EventHandler + Send + Sync>>,
1864    // This maps the handles of colliders that have been deleted since the last
1865    // physics update, to the entity they was attached to.
1866    /// NOTE: this map is needed to handle despawning.
1867    #[cfg_attr(feature = "serde-serialize", serde(skip))]
1868    pub(crate) deleted_colliders: HashMap<ColliderHandle, Entity>,
1869
1870    #[cfg_attr(feature = "serde-serialize", serde(skip))]
1871    pub(crate) collision_events_to_send: Vec<CollisionEvent>,
1872    #[cfg_attr(feature = "serde-serialize", serde(skip))]
1873    pub(crate) contact_force_events_to_send: Vec<ContactForceEvent>,
1874    #[cfg_attr(feature = "serde-serialize", serde(skip))]
1875    pub(crate) character_collisions_collector: Vec<rapier::control::CharacterCollision>,
1876    #[cfg_attr(feature = "serde-serialize", serde(skip))]
1877    pub(crate) step_stats: SimulationStepStats,
1878    /// Rigid-body entities quarantined since the last quarantine event was sent.
1879    #[cfg_attr(feature = "serde-serialize", serde(skip))]
1880    pub(crate) quarantined_bodies: Vec<Entity>,
1881    /// Collider entities quarantined since the last quarantine event was sent.
1882    #[cfg_attr(feature = "serde-serialize", serde(skip))]
1883    pub(crate) quarantined_colliders: Vec<Entity>,
1884    /// Soft-body entities quarantined since the last quarantine event was sent.
1885    #[cfg_attr(feature = "serde-serialize", serde(skip))]
1886    pub(crate) quarantined_soft_bodies: Vec<Entity>,
1887    /// The number of threads last requested through [`Self::set_num_threads`].
1888    #[cfg_attr(feature = "serde-serialize", serde(skip))]
1889    pub(crate) requested_num_threads: Option<usize>,
1890    /// Soft-body tears not yet turned into [`SoftBodyTearEvent`] messages (their piece entities
1891    /// are spawned by the `handle_soft_body_tears` system).
1892    ///
1893    /// [`SoftBodyTearEvent`]: crate::pipeline::SoftBodyTearEvent
1894    #[cfg_attr(feature = "serde-serialize", serde(skip))]
1895    pub(crate) pending_soft_body_tears: Vec<PendingSoftBodyTear>,
1896}
1897
1898impl Default for RapierContextSimulation {
1899    fn default() -> Self {
1900        Self {
1901            islands: IslandManager::new(),
1902            broad_phase: DefaultBroadPhase::new(),
1903            narrow_phase: NarrowPhase::new(),
1904            ccd_solver: CCDSolver::new(),
1905            pipeline: PhysicsPipeline::new(),
1906            collision_pipeline: CollisionPipeline::new(),
1907            integration_parameters: IntegrationParameters::default(),
1908            event_handler: None,
1909            deleted_colliders: HashMap::default(),
1910            collision_events_to_send: Vec::new(),
1911            contact_force_events_to_send: Vec::new(),
1912            character_collisions_collector: Vec::new(),
1913            step_stats: SimulationStepStats::default(),
1914            quarantined_bodies: Vec::new(),
1915            quarantined_colliders: Vec::new(),
1916            quarantined_soft_bodies: Vec::new(),
1917            requested_num_threads: None,
1918            pending_soft_body_tears: Vec::new(),
1919        }
1920    }
1921}
1922
1923impl RapierContextSimulation {
1924    /// Creates a simulation context whose broad-phase uses the given BVH optimization strategy.
1925    ///
1926    /// This is what [`RapierContextInitialization::InitializeDefaultRapierContext`] uses for the
1927    /// default context.
1928    ///
1929    /// [`RapierContextInitialization::InitializeDefaultRapierContext`]: crate::plugin::RapierContextInitialization::InitializeDefaultRapierContext
1930    pub fn with_broad_phase_optimization_strategy(
1931        strategy: BroadPhaseOptimizationStrategy,
1932    ) -> Self {
1933        Self {
1934            broad_phase: DefaultBroadPhase::with_optimization_strategy(strategy.into()),
1935            ..Self::default()
1936        }
1937    }
1938
1939    /// Statistics about the simulation steps executed during the last physics update.
1940    pub fn step_stats(&self) -> &SimulationStepStats {
1941        &self.step_stats
1942    }
1943
1944    /// Sets the number of threads of the thread pool dedicated to this context’s simulation, or
1945    /// removes that pool if `num_threads` is `None`.
1946    ///
1947    /// The pool is only rebuilt if `num_threads` differs from the value of the previous call. This
1948    /// is called automatically with [`RapierConfiguration::num_threads`] before each simulation
1949    /// step, and does nothing unless the `parallel` feature is enabled (and `unsync-callbacks`
1950    /// is not).
1951    ///
1952    /// [`RapierConfiguration::num_threads`]: crate::plugin::RapierConfiguration::num_threads
1953    pub fn set_num_threads(&mut self, num_threads: Option<usize>) {
1954        if self.requested_num_threads == num_threads {
1955            return;
1956        }
1957        self.requested_num_threads = num_threads;
1958
1959        #[cfg(all(feature = "parallel", not(feature = "unsync-callbacks")))]
1960        match num_threads {
1961            Some(n) => {
1962                if let Err(err) = self.pipeline.configure_thread_pool(n) {
1963                    log::error!("Failed to create a Rapier thread pool with {n} threads: {err}");
1964                }
1965            }
1966            None => self.pipeline.clear_thread_pool(),
1967        }
1968    }
1969
1970    /// Creates a simulation context whose narrow-phase uses a custom query dispatcher.
1971    ///
1972    /// The query dispatcher computes the contact manifolds and intersections between pairs of
1973    /// shapes, which makes it possible to support custom shapes or override the contact
1974    /// generation of existing ones. Spawn it with
1975    /// [`RapierContextInitialization::NoAutomaticRapierContext`](crate::plugin::RapierContextInitialization::NoAutomaticRapierContext),
1976    /// or see [`Self::set_query_dispatcher`] for the default context.
1977    pub fn with_query_dispatcher<D>(dispatcher: D) -> Self
1978    where
1979        D: 'static + PersistentQueryDispatcher<ContactManifoldData, ContactData>,
1980    {
1981        Self {
1982            narrow_phase: NarrowPhase::with_query_dispatcher(dispatcher),
1983            ..Self::default()
1984        }
1985    }
1986
1987    /// Replaces the narrow-phase with an empty one using the given custom query dispatcher.
1988    ///
1989    /// This discards every contact and intersection pair of the current narrow-phase, so it
1990    /// must be called before any collider is added to this context (for example in a
1991    /// `Startup` system, since colliders are inserted during [`PhysicsSet::SyncBackend`]).
1992    ///
1993    /// [`PhysicsSet::SyncBackend`]: crate::plugin::PhysicsSet::SyncBackend
1994    pub fn set_query_dispatcher<D>(&mut self, dispatcher: D)
1995    where
1996        D: 'static + PersistentQueryDispatcher<ContactManifoldData, ContactData>,
1997    {
1998        self.narrow_phase = NarrowPhase::with_query_dispatcher(dispatcher);
1999    }
2000
2001    /// The query dispatcher used by the narrow-phase to compute contacts and intersections.
2002    pub fn query_dispatcher(
2003        &self,
2004    ) -> &dyn PersistentQueryDispatcher<ContactManifoldData, ContactData> {
2005        self.narrow_phase.query_dispatcher()
2006    }
2007
2008    /// Installs a Rapier [`EventHandler`] called by the physics pipeline for every collision,
2009    /// contact force and soft-body tear event.
2010    ///
2011    /// It is called in addition to (not instead of) the forwarding of events as
2012    /// [`CollisionEvent`] and [`ContactForceEvent`] Bevy messages, and replaces the previously
2013    /// installed handler, if any. The handler receives raw Rapier handles: the entity of a
2014    /// collider can be retrieved with [`RapierContextColliders::entity_from_collider`]. Note that
2015    /// the colliders of an event flagged with `CollisionEventFlags::REMOVED` may no longer be
2016    /// part of the collider set.
2017    pub fn set_event_handler(&mut self, handler: impl EventHandler + Send + Sync + 'static) {
2018        self.event_handler = Some(Box::new(handler));
2019    }
2020
2021    /// Removes the event handler installed with [`Self::set_event_handler`] and returns it.
2022    pub fn remove_event_handler(&mut self) -> Option<Box<dyn EventHandler + Send + Sync>> {
2023        self.event_handler.take()
2024    }
2025
2026    /// The event handler installed with [`Self::set_event_handler`], if any.
2027    pub fn event_handler(&self) -> Option<&(dyn EventHandler + Send + Sync)> {
2028        self.event_handler.as_deref()
2029    }
2030
2031    /// Removes the soft body `handle` (with its colliders, cluster proxies and the joints
2032    /// attached to them), and unmaps the entities standing for them.
2033    pub(crate) fn remove_soft_body(
2034        &mut self,
2035        colliders: &mut RapierContextColliders,
2036        joints: &mut RapierContextJoints,
2037        rigidbody_set: &mut RapierRigidBodySet,
2038        handle: SoftBodyHandle,
2039    ) -> Option<RapierSoftBody> {
2040        let sb = rigidbody_set.soft_bodies.get(handle)?;
2041        for (_, cluster) in sb.live_clusters() {
2042            let proxy = cluster.proxy();
2043            let Some(rb) = rigidbody_set.bodies.get(proxy) else {
2044                continue;
2045            };
2046            if let Some(entity) = Entity::try_from_bits(rb.user_data as u64) {
2047                if rigidbody_set.entity2body.get(&entity) == Some(&proxy) {
2048                    rigidbody_set.entity2body.remove(&entity);
2049                    rigidbody_set.last_body_transform_set.remove(&proxy);
2050                }
2051            }
2052            for co_handle in rb.colliders() {
2053                let Some(co) = colliders.colliders.get(*co_handle) else {
2054                    continue;
2055                };
2056                let Some(entity) = Entity::try_from_bits(co.user_data as u64) else {
2057                    continue;
2058                };
2059                // Removed colliders may still be reported by the next step's events.
2060                self.deleted_colliders.insert(*co_handle, entity);
2061                if colliders.entity2collider.get(&entity) == Some(co_handle) {
2062                    colliders.entity2collider.remove(&entity);
2063                }
2064            }
2065            for (_, _, joint_handle, joint) in joints.impulse_joints.attached_joints(proxy) {
2066                let entity = RapierContextJoints::entity_from_impulse_joint(joint);
2067                if joints.entity2impulse_joint.get(&entity) == Some(&joint_handle) {
2068                    joints.entity2impulse_joint.remove(&entity);
2069                }
2070            }
2071        }
2072        rigidbody_set.entity2soft_body.retain(|_, h| *h != handle);
2073        rigidbody_set.soft_bodies.remove(
2074            handle,
2075            &mut self.islands,
2076            &mut rigidbody_set.bodies,
2077            &mut colliders.colliders,
2078            &mut joints.impulse_joints,
2079            &mut joints.multibody_joints,
2080        )
2081    }
2082
2083    /// Tears the soft body of `entity` right away along the given edges and through the given
2084    /// cells (see [`SoftBodySet::tear`]).
2085    ///
2086    /// The entities of the pieces split off the soft body are spawned with `commands` and
2087    /// returned right away; they get their components and a
2088    /// [`SoftBodyTearEvent`](crate::pipeline::SoftBodyTearEvent) message is sent during the next
2089    /// [`PhysicsSet::Writeback`](crate::plugin::PhysicsSet::Writeback) (see
2090    /// [`SoftBodyTearResult`]). Returns `None` if `entity` has no soft body or if nothing changed.
2091    #[allow(clippy::too_many_arguments)]
2092    pub fn tear_soft_body(
2093        &mut self,
2094        colliders: &mut RapierContextColliders,
2095        joints: &mut RapierContextJoints,
2096        rigidbody_set: &mut RapierRigidBodySet,
2097        commands: &mut Commands,
2098        entity: Entity,
2099        edges: &[u32],
2100        cells: &[u32],
2101    ) -> Option<SoftBodyTearResult> {
2102        let handle = *rigidbody_set.entity2soft_body.get(&entity)?;
2103        let event = rigidbody_set.soft_bodies.tear(
2104            handle,
2105            edges,
2106            cells,
2107            &mut self.islands,
2108            &mut rigidbody_set.bodies,
2109            &mut colliders.colliders,
2110            &mut joints.impulse_joints,
2111            &mut joints.multibody_joints,
2112        )?;
2113        Some(self.map_manual_tear(colliders, rigidbody_set, commands, entity, event))
2114    }
2115
2116    /// Cuts the soft body of `entity` right away along a blade: a world-space segment in 2D, a
2117    /// world-space triangle in 3D (see [`SoftBodySet::cut`]).
2118    ///
2119    /// The entities of the pieces split off the soft body are spawned with `commands` and
2120    /// returned right away; they get their components and a
2121    /// [`SoftBodyTearEvent`](crate::pipeline::SoftBodyTearEvent) message is sent during the next
2122    /// [`PhysicsSet::Writeback`](crate::plugin::PhysicsSet::Writeback) (see
2123    /// [`SoftBodyTearResult`]). Returns `None` if `entity` has no soft body or if nothing changed.
2124    pub fn cut_soft_body(
2125        &mut self,
2126        colliders: &mut RapierContextColliders,
2127        joints: &mut RapierContextJoints,
2128        rigidbody_set: &mut RapierRigidBodySet,
2129        commands: &mut Commands,
2130        entity: Entity,
2131        blade: &[Vect; rapier::math::DIM],
2132    ) -> Option<SoftBodyTearResult> {
2133        let handle = *rigidbody_set.entity2soft_body.get(&entity)?;
2134        let event = rigidbody_set.soft_bodies.cut(
2135            handle,
2136            blade,
2137            &mut self.islands,
2138            &mut rigidbody_set.bodies,
2139            &mut colliders.colliders,
2140            &mut joints.impulse_joints,
2141            &mut joints.multibody_joints,
2142        )?;
2143        Some(self.map_manual_tear(colliders, rigidbody_set, commands, entity, event))
2144    }
2145
2146    /// Spawns the entities of the pieces of a tear of the soft body of `entity`, maps them to their
2147    /// soft bodies, and queues the tear for the `handle_soft_body_tears` system.
2148    fn map_manual_tear(
2149        &mut self,
2150        colliders: &mut RapierContextColliders,
2151        rigidbody_set: &mut RapierRigidBodySet,
2152        commands: &mut Commands,
2153        entity: Entity,
2154        event: RapierSoftBodyTearEvent,
2155    ) -> SoftBodyTearResult {
2156        let mut pieces = Vec::with_capacity(event.pieces.len());
2157        for (k, piece) in event.pieces.iter().enumerate() {
2158            let piece_entity = if k == 0 {
2159                entity
2160            } else {
2161                let piece_entity = commands.spawn_empty().id();
2162                rigidbody_set.map_soft_body_piece(colliders, piece.soft_body, piece_entity);
2163                piece_entity
2164            };
2165            rigidbody_set.map_soft_body_collision_mesh(colliders, piece.soft_body, piece_entity);
2166            rigidbody_set.map_soft_body_whole_proxy(piece_entity, piece.soft_body);
2167            pieces.push(piece_entity);
2168        }
2169        if event.pieces.is_empty() {
2170            rigidbody_set.map_soft_body_collision_mesh(colliders, event.soft_body, entity);
2171            rigidbody_set.map_soft_body_whole_proxy(entity, event.soft_body);
2172        }
2173        self.pending_soft_body_tears.push(PendingSoftBodyTear {
2174            raw: event.clone(),
2175            piece_entities: pieces.get(1..).unwrap_or_default().to_vec(),
2176        });
2177        SoftBodyTearResult { pieces, raw: event }
2178    }
2179
2180    /// Advance the simulation, based on the given timestep mode.
2181    ///
2182    /// With [`SimulationMode::CollisionOnly`], only collision detection runs at each step (see
2183    /// [`SimulationMode`]).
2184    ///
2185    /// Steps with a zero (or negative) dt, like the first frame with [`TimestepMode::Variable`],
2186    /// are skipped entirely.
2187    #[allow(clippy::too_many_arguments)]
2188    pub fn step_simulation(
2189        &mut self,
2190        colliders: &mut RapierContextColliders,
2191        joints: &mut RapierContextJoints,
2192        rigidbody_set: &mut RapierRigidBodySet,
2193        gravity: Vect,
2194        simulation_mode: SimulationMode,
2195        timestep_mode: TimestepMode,
2196        events: Option<(
2197            &MessageWriter<CollisionEvent>,
2198            &MessageWriter<ContactForceEvent>,
2199        )>,
2200        hooks: &dyn PhysicsHooks,
2201        time: &Time,
2202        sim_to_render_time: &mut SimulationToRenderTime,
2203        mut interpolation_query: Option<
2204            &mut Query<(&RapierRigidBodyHandle, &mut TransformInterpolation)>,
2205        >,
2206    ) {
2207        self.step_stats = SimulationStepStats::default();
2208
2209        // Temporarily move the event handling state out of `self` so it can be borrowed while
2210        // `self` is borrowed mutably by each step.
2211        let user_event_handler = self.event_handler.take();
2212        let deleted_colliders = std::mem::take(&mut self.deleted_colliders);
2213
2214        let event_queue = if events.is_some() {
2215            Some(EventQueue {
2216                deleted_colliders: &deleted_colliders,
2217                collision_events: RwLock::new(Vec::new()),
2218                contact_force_events: RwLock::new(Vec::new()),
2219            })
2220        } else {
2221            None
2222        };
2223
2224        let soft_body_tears = RwLock::new(Vec::new());
2225        let fan_out = EventHandlerFanOut {
2226            queue: event_queue.as_ref(),
2227            user: user_event_handler.as_deref(),
2228            soft_body_tears: &soft_body_tears,
2229        };
2230        let event_handler = &fan_out as &dyn EventHandler;
2231
2232        let mut executed_steps = 0;
2233        match timestep_mode {
2234            TimestepMode::Interpolated {
2235                dt,
2236                time_scale,
2237                substeps,
2238            } => {
2239                self.integration_parameters.dt = dt;
2240
2241                sim_to_render_time.diff += time.delta_secs();
2242
2243                while sim_to_render_time.diff > 0.0 {
2244                    // NOTE: in this comparison we do the same computations we
2245                    // will do for the next `while` iteration test, to make sure we
2246                    // don't get bit by potential float inaccuracy.
2247                    if sim_to_render_time.diff - dt <= 0.0 {
2248                        if let Some(interpolation_query) = interpolation_query.as_mut() {
2249                            // This is the last simulation step to be executed in the loop
2250                            // Update the previous state transforms
2251                            for (handle, mut interpolation) in interpolation_query.iter_mut() {
2252                                if let Some(body) = rigidbody_set.bodies.get(handle.0) {
2253                                    interpolation.start = Some(*body.position());
2254                                    interpolation.end = None;
2255                                }
2256                            }
2257                        }
2258                    }
2259
2260                    let mut substep_integration_parameters = self.integration_parameters;
2261                    substep_integration_parameters.dt = dt / (substeps as Real) * time_scale;
2262
2263                    // A zero `time_scale` would run zero-length steps; skip them.
2264                    let num_substeps = if substep_integration_parameters.dt > 0.0 {
2265                        substeps
2266                    } else {
2267                        0
2268                    };
2269
2270                    for _ in 0..num_substeps {
2271                        self.step_once(
2272                            simulation_mode,
2273                            gravity,
2274                            &substep_integration_parameters,
2275                            colliders,
2276                            joints,
2277                            rigidbody_set,
2278                            hooks,
2279                            event_handler,
2280                        );
2281                        executed_steps += 1;
2282                    }
2283
2284                    sim_to_render_time.diff -= dt;
2285                }
2286            }
2287            TimestepMode::Variable {
2288                max_dt,
2289                time_scale,
2290                substeps,
2291            } => {
2292                self.integration_parameters.dt = (time.delta_secs() * time_scale).min(max_dt);
2293
2294                let mut substep_integration_parameters = self.integration_parameters;
2295                substep_integration_parameters.dt /= substeps as Real;
2296
2297                // The first frame (or a zero `time_scale`) has a zero dt: skip the step, which
2298                // would only run a useless collision detection pass.
2299                let num_substeps = if substep_integration_parameters.dt > 0.0 {
2300                    substeps
2301                } else {
2302                    0
2303                };
2304
2305                for _ in 0..num_substeps {
2306                    self.step_once(
2307                        simulation_mode,
2308                        gravity,
2309                        &substep_integration_parameters,
2310                        colliders,
2311                        joints,
2312                        rigidbody_set,
2313                        hooks,
2314                        event_handler,
2315                    );
2316                    executed_steps += 1;
2317                }
2318            }
2319            TimestepMode::Fixed { dt, substeps } => {
2320                self.integration_parameters.dt = dt;
2321
2322                let mut substep_integration_parameters = self.integration_parameters;
2323                substep_integration_parameters.dt = dt / (substeps as Real);
2324
2325                let num_substeps = if substep_integration_parameters.dt > 0.0 {
2326                    substeps
2327                } else {
2328                    0
2329                };
2330
2331                for _ in 0..num_substeps {
2332                    self.step_once(
2333                        simulation_mode,
2334                        gravity,
2335                        &substep_integration_parameters,
2336                        colliders,
2337                        joints,
2338                        rigidbody_set,
2339                        hooks,
2340                        event_handler,
2341                    );
2342                    executed_steps += 1;
2343                }
2344            }
2345        }
2346        if let Some(mut event_queue) = event_queue {
2347            // NOTE: event_queue and its inner locks are only accessed from
2348            // within the steps executed above, so we can unwrap here safely.
2349            self.collision_events_to_send =
2350                std::mem::take(event_queue.collision_events.get_mut().unwrap());
2351            self.contact_force_events_to_send =
2352                std::mem::take(event_queue.contact_force_events.get_mut().unwrap());
2353        }
2354
2355        // NOTE: the lock is only accessed from within the steps executed above.
2356        self.pending_soft_body_tears.extend(
2357            soft_body_tears
2358                .into_inner()
2359                .unwrap_or_default()
2360                .into_iter()
2361                .map(|raw| PendingSoftBodyTear {
2362                    raw,
2363                    piece_entities: vec![],
2364                }),
2365        );
2366
2367        self.event_handler = user_event_handler;
2368        if executed_steps == 0 {
2369            self.deleted_colliders = deleted_colliders;
2370            // No step ran (e.g. zero dt): still move colliders attached to bodies the user moved,
2371            // like when the physics pipeline is inactive.
2372            rigidbody_set.propagate_modified_body_positions_to_colliders(colliders);
2373        }
2374    }
2375
2376    /// Executes a single simulation step (or collision-detection step) and updates the step
2377    /// statistics and quarantine reports.
2378    #[allow(clippy::too_many_arguments)]
2379    fn step_once(
2380        &mut self,
2381        simulation_mode: SimulationMode,
2382        gravity: Vect,
2383        integration_parameters: &IntegrationParameters,
2384        colliders: &mut RapierContextColliders,
2385        joints: &mut RapierContextJoints,
2386        rigidbody_set: &mut RapierRigidBodySet,
2387        hooks: &dyn PhysicsHooks,
2388        event_handler: &dyn EventHandler,
2389    ) {
2390        let start = bevy::platform::time::Instant::now();
2391
2392        match simulation_mode {
2393            SimulationMode::Full => {
2394                self.pipeline.step(
2395                    gravity,
2396                    integration_parameters,
2397                    &mut self.islands,
2398                    &mut self.broad_phase,
2399                    &mut self.narrow_phase,
2400                    &mut rigidbody_set.bodies,
2401                    &mut colliders.colliders,
2402                    &mut joints.impulse_joints,
2403                    &mut joints.multibody_joints,
2404                    &mut rigidbody_set.soft_bodies,
2405                    &mut self.ccd_solver,
2406                    hooks,
2407                    event_handler,
2408                );
2409            }
2410            SimulationMode::CollisionOnly => {
2411                apply_kinematic_targets(&mut rigidbody_set.bodies);
2412                self.collision_pipeline.step(
2413                    integration_parameters.prediction_distance(),
2414                    &mut self.islands,
2415                    &mut self.broad_phase,
2416                    &mut self.narrow_phase,
2417                    &mut rigidbody_set.bodies,
2418                    &mut colliders.colliders,
2419                    hooks,
2420                    event_handler,
2421                );
2422            }
2423        }
2424
2425        self.step_stats.num_steps += 1;
2426        self.step_stats.step_time_ms += start.elapsed().as_secs_f64() * 1000.0;
2427
2428        // Rapier doesn't reset its counters while they are disabled, so they would be stale.
2429        if self.pipeline.counters.enabled() {
2430            match simulation_mode {
2431                SimulationMode::Full => self.step_stats.accumulate_counters(&self.pipeline),
2432                // The collision pipeline has no counters.
2433                SimulationMode::CollisionOnly => {
2434                    self.step_stats.num_contact_pairs = self.narrow_phase.contact_pairs().count();
2435                }
2436            }
2437        }
2438
2439        if simulation_mode == SimulationMode::Full {
2440            let quarantine = self.pipeline.quarantine();
2441            if !quarantine.is_empty() {
2442                self.quarantined_bodies.extend(
2443                    quarantine
2444                        .bodies()
2445                        .iter()
2446                        .filter_map(|h| rigidbody_set.rigid_body_entity(*h)),
2447                );
2448                self.quarantined_colliders.extend(
2449                    quarantine
2450                        .colliders()
2451                        .iter()
2452                        .filter_map(|h| colliders.collider_entity(*h)),
2453                );
2454                self.quarantined_soft_bodies.extend(
2455                    quarantine
2456                        .soft_bodies()
2457                        .iter()
2458                        .filter_map(|h| rigidbody_set.soft_body_entity(*h)),
2459                );
2460            }
2461        }
2462    }
2463
2464    /// Sends a [`PhysicsQuarantineEvent`] (and logs a warning) if some rigid-bodies, colliders or
2465    /// soft bodies were quarantined by the simulation steps executed since the last call.
2466    ///
2467    /// `context` is the entity of this context. This is called automatically by the
2468    /// [`step_simulation`](crate::plugin::systems::step_simulation) system.
2469    pub fn send_quarantine_events(
2470        &mut self,
2471        context: Entity,
2472        quarantine_event_writer: &mut MessageWriter<PhysicsQuarantineEvent>,
2473    ) {
2474        if self.quarantined_bodies.is_empty()
2475            && self.quarantined_colliders.is_empty()
2476            && self.quarantined_soft_bodies.is_empty()
2477        {
2478            return;
2479        }
2480
2481        let event = PhysicsQuarantineEvent {
2482            context,
2483            bodies: std::mem::take(&mut self.quarantined_bodies),
2484            colliders: std::mem::take(&mut self.quarantined_colliders),
2485            soft_bodies: std::mem::take(&mut self.quarantined_soft_bodies),
2486        };
2487        log::warn!(
2488            "Rapier detected non-finite (NaN or infinite) state in context {context}; the \
2489            following rigid-bodies were rolled back and disabled: {:?}; the following colliders \
2490            were disabled: {:?}; the following soft bodies were disabled: {:?}.",
2491            event.bodies,
2492            event.colliders,
2493            event.soft_bodies
2494        );
2495        quarantine_event_writer.write(event);
2496    }
2497
2498    /// Generates bevy events for any physics interactions that have happened
2499    /// that are stored in the events list
2500    pub fn send_bevy_events(
2501        &mut self,
2502        collision_event_writer: &mut MessageWriter<CollisionEvent>,
2503        contact_force_event_writer: &mut MessageWriter<ContactForceEvent>,
2504    ) {
2505        for collision_event in self.collision_events_to_send.drain(..) {
2506            collision_event_writer.write(collision_event);
2507        }
2508        for contact_force_event in self.contact_force_events_to_send.drain(..) {
2509            contact_force_event_writer.write(contact_force_event);
2510        }
2511    }
2512
2513    /// Attempts to move shape, optionally sliding or climbing obstacles.
2514    ///
2515    /// The obstacles are the colliders of this context matching `filter`, detected with this
2516    /// context's [query dispatcher](Self::query_dispatcher).
2517    ///
2518    /// # Parameters
2519    /// * `colliders`, `rigidbody_set`: the collider and rigid-body sets of this context.
2520    /// * `movement`: the translational movement to apply.
2521    /// * `shape`: the shape to move.
2522    /// * `shape_translation`: the initial position of the shape.
2523    /// * `shape_rotation`: the rotation of the shape.
2524    /// * `shape_mass`: the mass of the shape to be considered by the impulse calculation if
2525    ///   `MoveShapeOptions::apply_impulse_to_dynamic_bodies` is set to true.
2526    /// * `options`: configures the behavior of the automatic sliding and climbing.
2527    /// * `filter`: selects the colliders the shape can collide with (exclude the collider or
2528    ///   rigid-body of the moved shape itself).
2529    /// * `events`: callback run on each obstacle hit by the shape on its path, once the
2530    ///   movement is computed.
2531    #[allow(clippy::too_many_arguments)]
2532    pub fn move_shape(
2533        &mut self,
2534        colliders: &mut RapierContextColliders,
2535        rigidbody_set: &mut RapierRigidBodySet,
2536        movement: Vect,
2537        shape: &(impl AsShape + ?Sized),
2538        shape_translation: Vect,
2539        shape_rotation: Rot,
2540        shape_mass: Real,
2541        options: &MoveShapeOptions,
2542        filter: QueryFilter,
2543        mut events: impl FnMut(CharacterCollision),
2544    ) -> MoveShapeOutput {
2545        let shape = shape.as_shape();
2546        assert!(
2547            options.up.length_squared() > 0.0,
2548            "The up vector must be non-zero."
2549        );
2550        let up = options.up.normalize();
2551        let autostep = options.autostep.map(|autostep| CharacterAutostep {
2552            max_height: autostep.max_height,
2553            min_width: autostep.min_width,
2554            include_dynamic_bodies: autostep.include_dynamic_bodies,
2555        });
2556        let controller = rapier::control::KinematicCharacterController {
2557            up,
2558            offset: options.offset,
2559            slide: options.slide,
2560            autostep,
2561            max_slope_climb_angle: options.max_slope_climb_angle,
2562            min_slope_slide_angle: options.min_slope_slide_angle,
2563            snap_to_ground: options.snap_to_ground,
2564            normal_nudge_factor: options.normal_nudge_factor,
2565        };
2566
2567        let dt = self.integration_parameters.dt;
2568        let collisions = &mut self.character_collisions_collector;
2569        collisions.clear();
2570
2571        let result = RapierQueryPipelineMut::new_scoped(
2572            &self.broad_phase,
2573            colliders,
2574            rigidbody_set,
2575            &filter,
2576            self.narrow_phase.query_dispatcher(),
2577            |mut query_pipeline| {
2578                let result = controller.move_shape(
2579                    dt,
2580                    &query_pipeline.query_pipeline.as_ref(),
2581                    shape,
2582                    &crate::utils::pose_from(shape_translation, shape_rotation),
2583                    movement,
2584                    |c| collisions.push(c),
2585                );
2586
2587                if options.apply_impulse_to_dynamic_bodies {
2588                    controller.solve_character_collision_impulses(
2589                        dt,
2590                        &mut query_pipeline.query_pipeline,
2591                        shape,
2592                        shape_mass,
2593                        collisions.iter(),
2594                    );
2595                }
2596
2597                result
2598            },
2599        );
2600
2601        for collision in collisions.iter() {
2602            if let Some(collision) =
2603                CharacterCollision::from_raw_with_set(&colliders.colliders, collision, true)
2604            {
2605                events(collision);
2606            }
2607        }
2608
2609        MoveShapeOutput {
2610            effective_translation: result.translation,
2611            grounded: result.grounded,
2612            is_sliding_down_slope: result.is_sliding_down_slope,
2613        }
2614    }
2615}
2616
2617/// Deserialization helpers rebuilding the entity maps skipped during serialization.
2618#[cfg(feature = "serde-serialize")]
2619mod serde_shadows {
2620    use super::*;
2621    use rapier::prelude::{ImpulseJointSet, MultibodyJointSet};
2622
2623    #[derive(Deserialize)]
2624    pub(super) struct RapierContextCollidersData {
2625        colliders: ColliderSet,
2626    }
2627
2628    impl From<RapierContextCollidersData> for RapierContextColliders {
2629        fn from(data: RapierContextCollidersData) -> Self {
2630            let mut result = Self {
2631                colliders: data.colliders,
2632                entity2collider: HashMap::default(),
2633            };
2634            result.rebuild_entity_maps();
2635            result
2636        }
2637    }
2638
2639    #[derive(Deserialize)]
2640    pub(super) struct RapierContextJointsData {
2641        impulse_joints: ImpulseJointSet,
2642        multibody_joints: MultibodyJointSet,
2643    }
2644
2645    impl From<RapierContextJointsData> for RapierContextJoints {
2646        fn from(data: RapierContextJointsData) -> Self {
2647            let mut result = Self {
2648                impulse_joints: data.impulse_joints,
2649                multibody_joints: data.multibody_joints,
2650                entity2impulse_joint: HashMap::default(),
2651                entity2multibody_joint: HashMap::default(),
2652            };
2653            result.rebuild_entity_maps();
2654            result
2655        }
2656    }
2657
2658    #[derive(Deserialize)]
2659    pub(super) struct RapierRigidBodySetData {
2660        bodies: RigidBodySet,
2661        soft_bodies: SoftBodySet,
2662    }
2663
2664    impl From<RapierRigidBodySetData> for RapierRigidBodySet {
2665        fn from(data: RapierRigidBodySetData) -> Self {
2666            let mut result = Self {
2667                bodies: data.bodies,
2668                soft_bodies: data.soft_bodies,
2669                entity2body: HashMap::default(),
2670                entity2soft_body: HashMap::default(),
2671                last_body_transform_set: HashMap::default(),
2672            };
2673            result.rebuild_entity_maps();
2674            result
2675        }
2676    }
2677}