diff --git a/bevy_rapier3d/examples/ray_casting3.rs b/bevy_rapier3d/examples/ray_casting3.rs index 19acc10d..89d22377 100644 --- a/bevy_rapier3d/examples/ray_casting3.rs +++ b/bevy_rapier3d/examples/ray_casting3.rs @@ -76,7 +76,7 @@ pub fn setup_physics(mut commands: Commands) { pub fn cast_ray( mut commands: Commands, windows: Query<&Window, With>, - rapier_context: DefaultRapierContextAccessMut, + rapier_context: DefaultRapierContextAccess, cameras: Query<(&Camera, &GlobalTransform)>, ) { let window = windows.single(); diff --git a/src/plugin/context/mod.rs b/src/plugin/context/mod.rs index ec867c74..5d280ae2 100644 --- a/src/plugin/context/mod.rs +++ b/src/plugin/context/mod.rs @@ -375,16 +375,13 @@ impl RapierContext { collision_event_writer: &mut EventWriter, contact_force_event_writer: &mut EventWriter, ) { - for collision_event in self.collision_events_to_send.iter() { - collision_event_writer.send(*collision_event); + for collision_event in self.collision_events_to_send.drain(..) { + collision_event_writer.send(collision_event); } - self.collision_events_to_send.clear(); - for contact_force_event in self.contact_force_events_to_send.iter() { - contact_force_event_writer.send(*contact_force_event); + for contact_force_event in self.contact_force_events_to_send.drain(..) { + contact_force_event_writer.send(contact_force_event); } - - self.contact_force_events_to_send.clear(); } /// This method makes sure that the rigid-body positions have been propagated to diff --git a/src/plugin/context/systemparams/rapier_context_access.rs b/src/plugin/context/systemparams/rapier_context_access.rs index 7ea7958f..04f5cf06 100644 --- a/src/plugin/context/systemparams/rapier_context_access.rs +++ b/src/plugin/context/systemparams/rapier_context_access.rs @@ -3,14 +3,20 @@ use bevy::prelude::*; use std::ops::{Deref, DerefMut}; use super::super::{DefaultRapierContext, RapierContext, RapierContextEntityLink}; -/// Utility [`SystemParam`] to easily access the default world [`RapierContext`] immutably +/// Utility [`SystemParam`] to easily access the single default [`RapierContext`] immutably. +/// +/// SAFETY: Dereferencing this struct will panic if its underlying query fails. +/// See [`RapierContextAccess`] for a safer alternative. #[derive(SystemParam)] pub struct DefaultRapierContextAccess<'w, 's, T: Component = DefaultRapierContext> { rapier_context: Query<'w, 's, &'static RapierContext, With>, } impl<'w, 's, T: Component> DefaultRapierContextAccess<'w, 's, T> { - /// Use this method if you only have one world. + /// Use this method if you only have one [`RapierContext`]. + /// + /// SAFETY: This method will panic if its underlying query fails. + /// See [`RapierContextAccess`] for a safe alternative. pub fn single(&'_ self) -> &RapierContext { self.rapier_context.single() } @@ -19,12 +25,19 @@ impl<'w, 's, T: Component> DefaultRapierContextAccess<'w, 's, T> { impl<'w, 's> Deref for DefaultRapierContextAccess<'w, 's> { type Target = RapierContext; + /// Use this method if you only have one [`RapierContext`]. + /// + /// SAFETY: This method will panic if its underlying query fails. + /// See [`RapierContextAccess`] for a safe alternative. fn deref(&self) -> &Self::Target { self.rapier_context.single() } } -/// Utility [`SystemParam`] to easily access the default world [`RapierContext`] mutably +/// Utility [`SystemParam`] to easily access the single default [`RapierContext`] mutably. +/// +/// SAFETY: Dereferencing this struct will panic if its underlying query fails. +/// See [`RapierContextAccess`] for a safer alternative. #[derive(SystemParam)] pub struct DefaultRapierContextAccessMut<'w, 's, T: Component = DefaultRapierContext> { rapier_context: Query<'w, 's, &'static mut RapierContext, With>, @@ -33,12 +46,20 @@ pub struct DefaultRapierContextAccessMut<'w, 's, T: Component = DefaultRapierCon impl<'w, 's, T: Component> Deref for DefaultRapierContextAccessMut<'w, 's, T> { type Target = RapierContext; + /// Use this method if you only have one [`RapierContext`]. + /// + /// SAFETY: This method will panic if its underlying query fails. + /// See [`RapierContextAccess`] for a safe alternative. fn deref(&self) -> &Self::Target { self.rapier_context.single() } } impl<'w, 's> DerefMut for DefaultRapierContextAccessMut<'w, 's> { + /// Use this method if you only have one [`RapierContext`]. + /// + /// SAFETY: This method will panic if its underlying query fails. + /// See [`RapierContextAccess`] for a safe alternative. fn deref_mut(&mut self) -> &mut Self::Target { // TODO: should we cache the result ? self.rapier_context.single_mut().into_inner() @@ -58,11 +79,18 @@ pub struct RapierContextAccess<'w, 's> { impl<'w, 's> RapierContextAccess<'w, 's> { /// Retrieves the rapier context responsible for the entity owning the given [`RapierContextEntityLink`]. - pub fn context(&self, link: RapierContextEntityLink) -> &'_ RapierContext { - self.rapier_context - .get(link.0) + /// + /// SAFETY: This method will panic if its underlying query fails. + /// See [`Self::try_context`] for a safe alternative. + pub fn context(&self, link: &RapierContextEntityLink) -> &'_ RapierContext { + self.try_context(link) .expect("RapierContextEntityLink.0 refers to an entity without RapierContext.") } + + /// Retrieves the rapier context responsible for the entity owning the given [`RapierContextEntityLink`]. + pub fn try_context(&self, link: &RapierContextEntityLink) -> Option<&'_ RapierContext> { + self.rapier_context.get(link.0).ok() + } } impl<'w, 's> Deref for RapierContextAccess<'w, 's> { @@ -86,40 +114,54 @@ pub struct RapierContextAccessMut<'w, 's> { impl<'w, 's> RapierContextAccessMut<'w, 's> { /// Retrieves the rapier context responsible for the entity owning the given [`RapierContextEntityLink`]. - pub fn context(&mut self, link: RapierContextEntityLink) -> &'_ mut RapierContext { - self.rapier_context - .get_mut(link.0) + /// + /// SAFETY: This method will panic if its underlying query fails. + /// See [`Self::try_context`] for a safe alternative. + pub fn context(&mut self, link: &RapierContextEntityLink) -> Mut { + self.try_context(link) .expect("RapierContextEntityLink.0 refers to an entity without RapierContext.") - .into_inner() + } + + /// Retrieves the rapier context responsible for the entity owning the given [`RapierContextEntityLink`]. + pub fn try_context(&mut self, link: &RapierContextEntityLink) -> Option> { + self.rapier_context.get_mut(link.0).ok() } /// Retrieves the rapier context component on this [`Entity`]. /// - /// Do not call this on a rapier managed entity. given entity should have a [`RapierContext`]. + /// Calling this method on a rapier managed entity (rigid body, collider, joints...) will fail. + /// Given entity should have a [`RapierContext`]. + /// + /// SAFETY: This method will panic if its underlying query fails. pub(crate) fn context_from_entity( &mut self, rapier_context_entity: Entity, - ) -> &'_ mut RapierContext { - self.rapier_context - .get_mut(rapier_context_entity) - .unwrap_or_else(|_| panic!("entity {rapier_context_entity} has no RapierContext.")) - .into_inner() + ) -> Mut { + self.try_context_from_entity(rapier_context_entity) + .unwrap_or_else(|| panic!("entity {rapier_context_entity} has no RapierContext.")) + } + + /// Retrieves the rapier context component on this [`Entity`]. + /// + /// Calling this method on a rapier managed entity (rigid body, collider, joints...) will fail. + /// Given entity should have a [`RapierContext`]. + pub fn try_context_from_entity( + &mut self, + rapier_context_entity: Entity, + ) -> Option> { + self.rapier_context.get_mut(rapier_context_entity).ok() } } -pub fn try_get_default_context( +/// Gets the default RapierContext. +/// +/// SAFETY: Panics if no entity with [`DefaultRapierContext`] exist. +pub fn get_single_context( default_context_access: &Query>, -) -> Option { - let context_entity = match default_context_access.iter().next() { - Some(it) => it, - None => { - log::error!( - "No entity with `DefaultRapierContext` found.\ +) -> Entity { + default_context_access.get_single().expect( + "No entity with `DefaultRapierContext` found.\ Please add a default `RapierContext` or a `RapierContextEntityLink`\ - on the new rapier-managed entity." - ); - return None; - } - }; - Some(context_entity) + on the new rapier-managed entity.", + ) } diff --git a/src/plugin/plugin.rs b/src/plugin/plugin.rs index b58ab001..ce9be990 100644 --- a/src/plugin/plugin.rs +++ b/src/plugin/plugin.rs @@ -109,7 +109,6 @@ where .in_set(RapierTransformPropagateSet), systems::on_add_entity_with_parent, systems::on_change_world, - // systems::sync_removals, #[cfg(all(feature = "dim3", feature = "async-collider"))] systems::init_async_scene_colliders, @@ -118,8 +117,6 @@ where systems::init_rigid_bodies, systems::init_colliders, systems::init_joints, - //systems::sync_removals, - // Run this here so the following systems do not have a 1 frame delay. systems::apply_scale, systems::apply_collider_user_changes, systems::apply_rigid_body_user_changes, @@ -246,20 +243,6 @@ where .before(TransformSystem::TransformPropagate), ); - // These *must* be in the main schedule currently so that they do not miss events. - /*app.add_systems( - PostUpdate, - ( - // Change any worlds needed before doing any calculations - systems::on_add_entity_with_parent, - systems::on_change_world, - // Make sure to remove any dead bodies after changing_worlds but before everything else - // to avoid it deleting something right after adding it - //systems::sync_removals, - ) - .chain(), - );*/ - app.add_systems( self.schedule, ( @@ -287,12 +270,15 @@ where /// Specifies a default configuration for the default `RapierContext` /// -/// If [`None`], no world will be initialized, you are responsible of creating and maintaining -/// a [`RapierContext`] before creating any rapier entities (rigidbodies, colliders, joints), -/// and as long as any [`RapierContextEntityLink`] has a reference to its [`RapierContext`]. +/// If [`NoAutomaticRapierContext`], #[derive(Resource, Debug, Reflect, Clone)] pub enum RapierContextInitialization { /// [`RapierPhysicsPlugin`] will not spawn any entity containing [`RapierContext`] automatically. + /// + /// You are responsible for creating a [`RapierContext`], + /// before spawning any rapier entities (rigidbodies, colliders, joints). + /// + /// You might be interested in adding [`DefaultRapierContext`] to the created world. NoAutomaticRapierContext, /// [`RapierPhysicsPlugin`] will spawn an entity containing a [`RapierContext`] /// automatically during [`PreStartup`], with the [`DefaultRapierContext`] marker component. diff --git a/src/plugin/systems/character_controller.rs b/src/plugin/systems/character_controller.rs index f46c4dc1..de67606b 100644 --- a/src/plugin/systems/character_controller.rs +++ b/src/plugin/systems/character_controller.rs @@ -39,11 +39,13 @@ pub fn update_character_controls( glob_transform, ) in character_controllers.iter_mut() { - let context = context_access.context(*rapier_context_link); - let config = config.get(rapier_context_link.0).unwrap(); if let (Some(raw_controller), Some(translation)) = (controller.to_raw(), controller.translation) { + let config = config + .get(rapier_context_link.0) + .expect("Could not get [`RapierConfiguration`]"); + let context = context_access.context(rapier_context_link).into_inner(); let scaled_custom_shape = controller .custom_shape diff --git a/src/plugin/systems/collider.rs b/src/plugin/systems/collider.rs index 3bc44e8b..d6061e3b 100644 --- a/src/plugin/systems/collider.rs +++ b/src/plugin/systems/collider.rs @@ -1,6 +1,6 @@ use crate::dynamics::ReadMassProperties; use crate::geometry::Collider; -use crate::plugin::context::systemparams::{try_get_default_context, RapierEntity}; +use crate::plugin::context::systemparams::{get_single_context, RapierEntity}; use crate::plugin::context::RapierContextEntityLink; use crate::plugin::{ DefaultRapierContext, RapierConfiguration, RapierContext, RapierContextAccessMut, @@ -143,7 +143,9 @@ pub fn apply_collider_user_changes( mut mass_modified: EventWriter, ) { for (rapier_entity, handle, transform) in changed_collider_transforms.iter() { - let context = context.context(*rapier_entity.rapier_context_link); + let context = context + .context(rapier_entity.rapier_context_link) + .into_inner(); if context.collider_parent(rapier_entity.entity).is_some() { let (_, collider_position) = collider_offset( rapier_entity.entity, @@ -161,7 +163,9 @@ pub fn apply_collider_user_changes( } for (rapier_entity, handle, shape) in changed_shapes.iter() { - let context = context.context(*rapier_entity.rapier_context_link); + let context = context + .context(rapier_entity.rapier_context_link) + .into_inner(); let config = config.get(rapier_entity.rapier_context_link.0).unwrap(); if let Some(co) = context.colliders.get_mut(handle.0) { let mut scaled_shape = shape.clone(); @@ -177,28 +181,36 @@ pub fn apply_collider_user_changes( } for (rapier_entity, handle, active_events) in changed_active_events.iter() { - let context = context.context(*rapier_entity.rapier_context_link); + let context = context + .context(rapier_entity.rapier_context_link) + .into_inner(); if let Some(co) = context.colliders.get_mut(handle.0) { co.set_active_events((*active_events).into()) } } for (rapier_entity, handle, active_hooks) in changed_active_hooks.iter() { - let context = context.context(*rapier_entity.rapier_context_link); + let context = context + .context(rapier_entity.rapier_context_link) + .into_inner(); if let Some(co) = context.colliders.get_mut(handle.0) { co.set_active_hooks((*active_hooks).into()) } } for (rapier_entity, handle, active_collision_types) in changed_active_collision_types.iter() { - let context = context.context(*rapier_entity.rapier_context_link); + let context = context + .context(rapier_entity.rapier_context_link) + .into_inner(); if let Some(co) = context.colliders.get_mut(handle.0) { co.set_active_collision_types((*active_collision_types).into()) } } for (rapier_entity, handle, friction) in changed_friction.iter() { - let context = context.context(*rapier_entity.rapier_context_link); + let context = context + .context(rapier_entity.rapier_context_link) + .into_inner(); if let Some(co) = context.colliders.get_mut(handle.0) { co.set_friction(friction.coefficient); co.set_friction_combine_rule(friction.combine_rule.into()); @@ -206,7 +218,9 @@ pub fn apply_collider_user_changes( } for (rapier_entity, handle, restitution) in changed_restitution.iter() { - let context = context.context(*rapier_entity.rapier_context_link); + let context = context + .context(rapier_entity.rapier_context_link) + .into_inner(); if let Some(co) = context.colliders.get_mut(handle.0) { co.set_restitution(restitution.coefficient); co.set_restitution_combine_rule(restitution.combine_rule.into()); @@ -214,49 +228,63 @@ pub fn apply_collider_user_changes( } for (rapier_entity, handle, contact_skin) in changed_contact_skin.iter() { - let context = context.context(*rapier_entity.rapier_context_link); + let context = context + .context(rapier_entity.rapier_context_link) + .into_inner(); if let Some(co) = context.colliders.get_mut(handle.0) { co.set_contact_skin(contact_skin.0); } } for (rapier_entity, handle, collision_groups) in changed_collision_groups.iter() { - let context = context.context(*rapier_entity.rapier_context_link); + let context = context + .context(rapier_entity.rapier_context_link) + .into_inner(); if let Some(co) = context.colliders.get_mut(handle.0) { co.set_collision_groups((*collision_groups).into()); } } for (rapier_entity, handle, solver_groups) in changed_solver_groups.iter() { - let context = context.context(*rapier_entity.rapier_context_link); + let context = context + .context(rapier_entity.rapier_context_link) + .into_inner(); if let Some(co) = context.colliders.get_mut(handle.0) { co.set_solver_groups((*solver_groups).into()); } } for (rapier_entity, handle, _) in changed_sensors.iter() { - let context = context.context(*rapier_entity.rapier_context_link); + let context = context + .context(rapier_entity.rapier_context_link) + .into_inner(); if let Some(co) = context.colliders.get_mut(handle.0) { co.set_sensor(true); } } for (rapier_entity, handle, _) in changed_disabled.iter() { - let context = context.context(*rapier_entity.rapier_context_link); + let context = context + .context(rapier_entity.rapier_context_link) + .into_inner(); if let Some(co) = context.colliders.get_mut(handle.0) { co.set_enabled(false); } } for (rapier_entity, handle, threshold) in changed_contact_force_threshold.iter() { - let context = context.context(*rapier_entity.rapier_context_link); + let context = context + .context(rapier_entity.rapier_context_link) + .into_inner(); if let Some(co) = context.colliders.get_mut(handle.0) { co.set_contact_force_event_threshold(threshold.0); } } for (rapier_entity, handle, mprops) in changed_collider_mass_props.iter() { - let context = context.context(*rapier_entity.rapier_context_link); + let context = context + .context(rapier_entity.rapier_context_link) + .into_inner(); if let Some(co) = context.colliders.get_mut(handle.0) { match mprops { ColliderMassProperties::Density(density) => co.set_density(*density), @@ -344,7 +372,7 @@ pub fn init_colliders( { let context_entity = context_link.map_or_else( || { - let context_entity = try_get_default_context(&default_context).unwrap(); + let context_entity = get_single_context(&default_context); commands .entity(entity) .insert(RapierContextEntityLink(context_entity)); @@ -352,8 +380,12 @@ pub fn init_colliders( }, |link| link.0, ); - let context = context_access.context_from_entity(context_entity); - let config = config.get(context_entity).unwrap(); + let context = context_access + .context_from_entity(context_entity) + .into_inner(); + let config = config.get(context_entity).unwrap_or_else(|_| { + panic!("Failed to retrieve `RapierConfiguration` on entity {context_entity}.") + }); let mut scaled_shape = shape.clone(); scaled_shape.set_scale(shape.scale, config.scaled_shape_subdivision); let mut builder = ColliderBuilder::new(scaled_shape.raw.clone()); diff --git a/src/plugin/systems/joint.rs b/src/plugin/systems/joint.rs index e50bf211..e8fc8cb1 100644 --- a/src/plugin/systems/joint.rs +++ b/src/plugin/systems/joint.rs @@ -2,7 +2,7 @@ use crate::dynamics::ImpulseJoint; use crate::dynamics::MultibodyJoint; use crate::dynamics::RapierImpulseJointHandle; use crate::dynamics::RapierMultibodyJointHandle; -use crate::plugin::context::systemparams::try_get_default_context; +use crate::plugin::context::systemparams::get_single_context; use crate::plugin::context::RapierContextEntityLink; use crate::plugin::DefaultRapierContext; use crate::plugin::RapierContextAccessMut; @@ -26,7 +26,7 @@ pub fn init_joints( for (entity, entity_context_link, joint) in impulse_joints.iter() { let context_entity = entity_context_link.map_or_else( || { - let context_entity = try_get_default_context(&default_context).unwrap(); + let context_entity = get_single_context(&default_context); commands .entity(entity) .insert(RapierContextEntityLink(context_entity)); @@ -34,7 +34,9 @@ pub fn init_joints( }, |link| link.0, ); - let context = context_access.context_from_entity(context_entity); + let context = context_access + .context_from_entity(context_entity) + .into_inner(); let mut target = None; let mut body_entity = entity; while target.is_none() { @@ -61,7 +63,7 @@ pub fn init_joints( for (entity, entity_context_link, joint) in multibody_joints.iter() { let context_entity = entity_context_link.map_or_else( || { - let context_entity = try_get_default_context(&default_context).unwrap(); + let context_entity = get_single_context(&default_context); commands .entity(entity) .insert(RapierContextEntityLink(context_entity)); @@ -69,7 +71,9 @@ pub fn init_joints( }, |link| link.0, ); - let context = context_access.context_from_entity(context_entity); + let context = context_access + .context_from_entity(context_entity) + .into_inner(); let target = context.entity2body.get(&entity); if let (Some(target), Some(source)) = (target, context.entity2body.get(&joint.parent)) { @@ -112,14 +116,14 @@ pub fn apply_joint_user_changes( // TODO: right now, we only support propagating changes made to the joint data. // Re-parenting the joint isn’t supported yet. for (link, handle, changed_joint) in changed_impulse_joints.iter() { - let context = context.context(*link); + let context = context.context(link).into_inner(); if let Some(joint) = context.impulse_joints.get_mut(handle.0) { joint.data = changed_joint.data.into_rapier(); } } for (link, handle, changed_joint) in changed_multibody_joints.iter() { - let context = context.context(*link); + let context = context.context(link).into_inner(); // TODO: not sure this will always work properly, e.g., if the number of Dofs is changed. if let Some((mb, link_id)) = context.multibody_joints.get_mut(handle.0) { if let Some(link) = mb.link_mut(link_id) { diff --git a/src/plugin/systems/rigid_body.rs b/src/plugin/systems/rigid_body.rs index c8662824..f4b4154c 100644 --- a/src/plugin/systems/rigid_body.rs +++ b/src/plugin/systems/rigid_body.rs @@ -1,5 +1,4 @@ use crate::dynamics::RapierRigidBodyHandle; -use crate::plugin::context::systemparams::try_get_default_context; use crate::plugin::context::RapierContextEntityLink; use crate::plugin::{configuration::TimestepMode, RapierConfiguration, RapierContext}; use crate::{dynamics::RigidBody, plugin::configuration::SimulationToRenderTime}; @@ -40,7 +39,7 @@ pub type RigidBodyComponents<'a> = ( /// System responsible for applying changes the user made to a rigid-body-related component. pub fn apply_rigid_body_user_changes( - mut context: Query<&mut RapierContext>, + mut context: RapierContextAccessMut, config: Query<&RapierConfiguration>, changed_rb_types: Query< (&RapierRigidBodyHandle, &RapierContextEntityLink, &RigidBody), @@ -139,7 +138,7 @@ pub fn apply_rigid_body_user_changes( // Deal with sleeping first, because other changes may then wake-up the // rigid-body again. for (handle, link, sleeping) in changed_sleeping.iter() { - let mut context = context.get_mut(link.0).unwrap(); + let context = context.context(link).into_inner(); if let Some(rb) = context.bodies.get_mut(handle.0) { let activation = rb.activation_mut(); @@ -161,7 +160,7 @@ pub fn apply_rigid_body_user_changes( // changed to anything else, a transform change would modify the next // position instead of the current one. for (handle, link, rb_type) in changed_rb_types.iter() { - let mut context = context.get_mut(link.0).unwrap(); + let context = context.context(link).into_inner(); if let Some(rb) = context.bodies.get_mut(handle.0) { rb.set_body_type((*rb_type).into(), true); } @@ -186,8 +185,10 @@ pub fn apply_rigid_body_user_changes( }; for (handle, link, global_transform, mut interpolation) in changed_transforms.iter_mut() { - let context = &mut *context.get_mut(link.0).unwrap(); - let config = config.get(link.0).unwrap(); + let context = context.context(link).into_inner(); + let config = config + .get(link.0) + .expect("Could not get `RapierConfiguration`"); // Use an Option to avoid running the check twice. let mut transform_changed = None; @@ -246,7 +247,7 @@ pub fn apply_rigid_body_user_changes( } for (handle, link, velocity) in changed_velocities.iter() { - let mut context = context.get_mut(link.0).unwrap(); + let context = context.context(link).into_inner(); if let Some(rb) = context.bodies.get_mut(handle.0) { rb.set_linvel(velocity.linvel.into(), true); #[allow(clippy::useless_conversion)] // Need to convert if dim3 enabled @@ -255,7 +256,7 @@ pub fn apply_rigid_body_user_changes( } for (entity, link, handle, mprops) in changed_additional_mass_props.iter() { - let mut context = context.get_mut(link.0).unwrap(); + let context = context.context(link).into_inner(); if let Some(rb) = context.bodies.get_mut(handle.0) { match mprops { AdditionalMassProperties::MassProperties(mprops) => { @@ -271,21 +272,21 @@ pub fn apply_rigid_body_user_changes( } for (handle, link, additional_solver_iters) in changed_additional_solver_iterations.iter() { - let mut context = context.get_mut(link.0).unwrap(); + let context = context.context(link).into_inner(); if let Some(rb) = context.bodies.get_mut(handle.0) { rb.set_additional_solver_iterations(additional_solver_iters.0); } } for (handle, link, locked_axes) in changed_locked_axes.iter() { - let mut context = context.get_mut(link.0).unwrap(); + let context = context.context(link).into_inner(); if let Some(rb) = context.bodies.get_mut(handle.0) { rb.set_locked_axes((*locked_axes).into(), true); } } for (handle, link, forces) in changed_forces.iter() { - let mut context = context.get_mut(link.0).unwrap(); + let context = context.context(link).into_inner(); if let Some(rb) = context.bodies.get_mut(handle.0) { rb.reset_forces(true); rb.reset_torques(true); @@ -296,7 +297,7 @@ pub fn apply_rigid_body_user_changes( } for (handle, link, mut impulses) in changed_impulses.iter_mut() { - let mut context = context.get_mut(link.0).unwrap(); + let context = context.context(link).into_inner(); if let Some(rb) = context.bodies.get_mut(handle.0) { rb.apply_impulse(impulses.impulse.into(), true); #[allow(clippy::useless_conversion)] // Need to convert if dim3 enabled @@ -306,35 +307,35 @@ pub fn apply_rigid_body_user_changes( } for (handle, link, gravity_scale) in changed_gravity_scale.iter() { - let mut context = context.get_mut(link.0).unwrap(); + let context = context.context(link).into_inner(); if let Some(rb) = context.bodies.get_mut(handle.0) { rb.set_gravity_scale(gravity_scale.0, true); } } for (handle, link, ccd) in changed_ccd.iter() { - let mut context = context.get_mut(link.0).unwrap(); + let context = context.context(link).into_inner(); if let Some(rb) = context.bodies.get_mut(handle.0) { rb.enable_ccd(ccd.enabled); } } for (handle, link, soft_ccd) in changed_soft_ccd.iter() { - let mut context = context.get_mut(link.0).unwrap(); + let context = context.context(link).into_inner(); if let Some(rb) = context.bodies.get_mut(handle.0) { rb.set_soft_ccd_prediction(soft_ccd.prediction); } } for (handle, link, dominance) in changed_dominance.iter() { - let mut context = context.get_mut(link.0).unwrap(); + let context = context.context(link).into_inner(); if let Some(rb) = context.bodies.get_mut(handle.0) { rb.set_dominance_group(dominance.groups); } } for (handle, link, damping) in changed_damping.iter() { - let mut context = context.get_mut(link.0).unwrap(); + let context = context.context(link).into_inner(); if let Some(rb) = context.bodies.get_mut(handle.0) { rb.set_linear_damping(damping.linear_damping); rb.set_angular_damping(damping.angular_damping); @@ -342,7 +343,7 @@ pub fn apply_rigid_body_user_changes( } for (handle, link, _) in changed_disabled.iter() { - let mut context = context.get_mut(link.0).unwrap(); + let context = context.context(link).into_inner(); if let Some(co) = context.bodies.get_mut(handle.0) { co.set_enabled(false); } @@ -352,7 +353,7 @@ pub fn apply_rigid_body_user_changes( /// System responsible for writing the result of the last simulation step into our `bevy_rapier` /// components and the [`GlobalTransform`] component. pub fn writeback_rigid_bodies( - mut context: Query<&mut RapierContext>, + mut context: RapierContextAccessMut, timestep_mode: Res, config: Query<&RapierConfiguration>, sim_to_render_time: Query<&SimulationToRenderTime>, @@ -365,14 +366,18 @@ pub fn writeback_rigid_bodies( for (handle, link, parent, transform, mut interpolation, mut velocity, mut sleeping) in writeback.iter_mut() { - let config = config.get(link.0).unwrap(); + let config = config + .get(link.0) + .expect("Could not get `RapierConfiguration`"); if !config.physics_pipeline_active { continue; } let handle = handle.0; - let context = &mut *context.get_mut(link.0).unwrap(); - let sim_to_render_time = sim_to_render_time.get(link.0).unwrap(); + let context = context.context(link).into_inner(); + let sim_to_render_time = sim_to_render_time + .get(link.0) + .expect("Could not get `SimulationToRenderTime`"); // TODO: do this the other way round: iterate through Rapier’s RigidBodySet on the active bodies, // and update the components accordingly. That way, we don’t have to iterate through the entities that weren’t changed // by physics (for example because they are sleeping). @@ -604,7 +609,7 @@ pub fn init_rigid_bodies( // Get rapier context from RapierContextEntityLink or insert its default value. let context_entity = entity_context_link.map_or_else( || { - let context_entity = try_get_default_context(&default_context_access)?; + let context_entity = default_context_access.get_single().ok()?; commands .entity(entity) .insert(RapierContextEntityLink(context_entity)); @@ -647,7 +652,7 @@ pub fn apply_initial_rigid_body_impulses( >, ) { for (entity, link, mut impulse) in init_impulses.iter_mut() { - let context = context.context(*link); + let context = context.context(link).into_inner(); let bodies = &mut context.bodies; if let Some(rb) = context .entity2body diff --git a/src/plugin/systems/writeback.rs b/src/plugin/systems/writeback.rs index a14c5b66..f4eead69 100644 --- a/src/plugin/systems/writeback.rs +++ b/src/plugin/systems/writeback.rs @@ -2,24 +2,28 @@ use crate::dynamics::MassProperties; use crate::dynamics::ReadMassProperties; use crate::plugin::context::RapierContextEntityLink; use crate::plugin::RapierConfiguration; -use crate::plugin::RapierContext; +use crate::plugin::RapierContextAccess; use crate::prelude::MassModifiedEvent; use bevy::prelude::*; /// System responsible for writing updated mass properties back into the [`ReadMassProperties`] component. pub fn writeback_mass_properties( link: Query<&RapierContextEntityLink>, - context: Query<&RapierContext>, + context: RapierContextAccess, config: Query<&RapierConfiguration>, mut mass_props: Query<&mut ReadMassProperties>, mut mass_modified: EventReader, ) { for entity in mass_modified.read() { - let link = link.get(entity.0).unwrap(); - let config = config.get(link.0).unwrap(); + let link = link + .get(entity.0) + .expect("Could not find `RapierContextEntityLink`"); + let config = config + .get(link.0) + .expect("Could not find `RapierConfiguration`"); if config.physics_pipeline_active { - let context = context.get(link.0).unwrap(); + let context = context.context(link); if let Some(handle) = context.entity2body.get(entity).copied() { if let Some(rb) = context.bodies.get(handle) {