1use crate::dynamics::ImpulseJoint;
2use crate::dynamics::ImpulseJointDisabled;
3use crate::dynamics::MultibodyJoint;
4use crate::dynamics::RapierImpulseJointHandle;
5use crate::dynamics::RapierMultibodyJointHandle;
6use crate::dynamics::RapierRigidBodyHandle;
7use crate::dynamics::RigidBody;
8use crate::dynamics::SoftBody;
9use crate::dynamics::SoftBodyCluster;
10use crate::geometry::Collider;
11use crate::geometry::ColliderDisabled;
12use crate::geometry::RapierColliderHandle;
13use crate::plugin::context::{
14 RapierContextColliders, RapierContextJoints, RapierContextSimulation, RapierRigidBodySet,
15};
16#[cfg(feature = "dim3")]
17use crate::prelude::GyroscopicForces;
18use crate::prelude::{
19 ActiveCollisionTypes, ActiveEvents, ActiveHooks, AdditionalMassProperties,
20 AdditionalPgsIterations, AdditionalSolverIterations, AllowFastRotation, Ccd,
21 ColliderMassProperties, CollisionGroups, ContactForceEventThreshold, ContactSkin, Damping,
22 Dominance, ExternalForce, Friction, GravityScale, LockedAxes, MassModifiedEvent,
23 MassProperties, ReadColliderMassProperties, Restitution, RigidBodyDisabled, Sensor, Sleeping,
24 SoftCcd, SolverGroups,
25};
26use bevy::ecs::query::IterQueryData;
27use bevy::prelude::*;
28
29pub fn sync_removals(
33 mut commands: Commands,
34 mut context_writer: Query<(
35 &mut RapierContextSimulation,
36 &mut RapierContextColliders,
37 &mut RapierContextJoints,
38 &mut RapierRigidBodySet,
39 )>,
40 (
43 q_has_rigidbody_handle,
44 q_has_collider_handle,
45 q_has_multibody_joint_handle,
46 q_has_impulse_joint_handle,
47 ): (
48 Query<(), With<RapierRigidBodyHandle>>,
49 Query<(), With<RapierColliderHandle>>,
50 Query<(), With<RapierMultibodyJointHandle>>,
51 Query<(), With<RapierImpulseJointHandle>>,
52 ),
53 mut removed_bodies: RemovedComponents<RapierRigidBodyHandle>,
54 mut removed_colliders: RemovedComponents<RapierColliderHandle>,
55 mut removed_impulse_joints: RemovedComponents<RapierImpulseJointHandle>,
56 mut removed_multibody_joints: RemovedComponents<RapierMultibodyJointHandle>,
57 orphan_bodies: Query<
58 Entity,
59 (
60 With<RapierRigidBodyHandle>,
61 Without<RigidBody>,
62 Without<SoftBodyCluster>,
63 ),
64 >,
65 orphan_colliders: Query<Entity, (With<RapierColliderHandle>, Without<Collider>)>,
66 orphan_impulse_joints: Query<Entity, (With<RapierImpulseJointHandle>, Without<ImpulseJoint>)>,
67 orphan_multibody_joints: Query<
68 Entity,
69 (With<RapierMultibodyJointHandle>, Without<MultibodyJoint>),
70 >,
71
72 mut removed_sensors: RemovedComponents<Sensor>,
73 mut removed_rigid_body_disabled: RemovedComponents<RigidBodyDisabled>,
74 mut removed_colliders_disabled: RemovedComponents<ColliderDisabled>,
75 (mut removed_impulse_joints_disabled, mut impulse_joints): (
76 RemovedComponents<ImpulseJointDisabled>,
77 Query<&mut ImpulseJoint, Without<ImpulseJointDisabled>>,
78 ),
79
80 mut mass_modified: MessageWriter<MassModifiedEvent>,
81) {
82 for entity in removed_bodies
86 .read()
87 .filter(|e| !q_has_rigidbody_handle.contains(*e))
88 {
89 let Some(((mut context, mut context_colliders, mut joints, mut rigidbody_set), handle)) =
90 find_context(&mut context_writer, |res| res.3.entity2body.remove(&entity))
91 else {
92 continue;
93 };
94 let context = &mut *context;
95 let joints = &mut *joints;
96 let rigidbody_set = &mut *rigidbody_set;
97
98 let _ = rigidbody_set.last_body_transform_set.remove(&handle);
99 rigidbody_set.bodies.remove(
100 handle,
101 &mut context.islands,
102 &mut context_colliders.colliders,
103 &mut joints.impulse_joints,
104 &mut joints.multibody_joints,
105 &mut rigidbody_set.soft_bodies,
106 false,
107 );
108 }
109
110 for entity in orphan_bodies.iter() {
111 if let Some(((mut context, mut context_colliders, mut joints, mut rigidbody_set), handle)) =
112 find_context(&mut context_writer, |res| res.3.entity2body.remove(&entity))
113 {
114 let context = &mut *context;
115 let joints = &mut *joints;
116 let rigidbody_set = &mut *rigidbody_set;
117 let _ = rigidbody_set.last_body_transform_set.remove(&handle);
118 rigidbody_set.bodies.remove(
119 handle,
120 &mut context.islands,
121 &mut context_colliders.colliders,
122 &mut joints.impulse_joints,
123 &mut joints.multibody_joints,
124 &mut rigidbody_set.soft_bodies,
125 false,
126 );
127 }
128 commands.entity(entity).remove::<RapierRigidBodyHandle>();
129 }
130
131 for entity in removed_colliders
135 .read()
136 .filter(|e| !q_has_collider_handle.contains(*e))
137 {
138 let Some(((mut context, mut context_colliders, _, mut rigidbody_set), handle)) =
139 find_context(&mut context_writer, |res| {
140 res.1.entity2collider.remove(&entity)
141 })
142 else {
143 continue;
144 };
145 let context = &mut *context;
146 let rigidbody_set = &mut *rigidbody_set;
147 if let Some(parent) = context_colliders.collider_parent(rigidbody_set, entity) {
148 mass_modified.write(parent.into());
149 }
150
151 context_colliders.colliders.remove(
152 handle,
153 &mut context.islands,
154 &mut rigidbody_set.bodies,
155 &mut rigidbody_set.soft_bodies,
156 true,
157 );
158 context.deleted_colliders.insert(handle, entity);
159 }
160
161 for entity in orphan_colliders.iter() {
162 if let Some(((mut context, mut context_colliders, _, mut rigidbody_set), handle)) =
163 find_context(&mut context_writer, |res| {
164 res.1.entity2collider.remove(&entity)
165 })
166 {
167 let context = &mut *context;
168 let context_colliders = &mut *context_colliders;
169 let rigidbody_set = &mut *rigidbody_set;
170 if let Some(parent) = context_colliders.collider_parent(rigidbody_set, entity) {
171 mass_modified.write(parent.into());
172 }
173
174 context_colliders.colliders.remove(
175 handle,
176 &mut context.islands,
177 &mut rigidbody_set.bodies,
178 &mut rigidbody_set.soft_bodies,
179 true,
180 );
181 context.deleted_colliders.insert(handle, entity);
182 }
183 commands.entity(entity).remove::<RapierColliderHandle>();
184 }
185
186 for entity in removed_impulse_joints
190 .read()
191 .filter(|e| !q_has_impulse_joint_handle.contains(*e))
192 {
193 let Some(((_, _, mut joints, _), handle)) = find_context(&mut context_writer, |res| {
194 res.2.entity2impulse_joint.remove(&entity)
195 }) else {
196 continue;
197 };
198 joints.impulse_joints.remove(handle, true);
199 }
200
201 for entity in orphan_impulse_joints.iter() {
202 if let Some(((_, _, mut joints, _), handle)) = find_context(&mut context_writer, |res| {
203 res.2.entity2impulse_joint.remove(&entity)
204 }) {
205 joints.impulse_joints.remove(handle, true);
206 }
207 commands.entity(entity).remove::<RapierImpulseJointHandle>();
208 }
209
210 for entity in removed_multibody_joints
214 .read()
215 .filter(|e| !q_has_multibody_joint_handle.contains(*e))
216 {
217 let Some(((_, _, mut joints, _), handle)) = find_context(&mut context_writer, |res| {
218 res.2.entity2multibody_joint.remove(&entity)
219 }) else {
220 continue;
221 };
222 joints.multibody_joints.remove(handle, true);
223 }
224
225 for entity in orphan_multibody_joints.iter() {
226 if let Some(((_, _, mut joints, _), handle)) = find_context(&mut context_writer, |res| {
227 res.2.entity2multibody_joint.remove(&entity)
228 }) {
229 joints.multibody_joints.remove(handle, true);
230 }
231 commands
232 .entity(entity)
233 .remove::<RapierMultibodyJointHandle>();
234 }
235
236 for entity in removed_sensors.read() {
240 for (_, mut colliders, _, rigidbody_set) in context_writer.iter_mut() {
241 let handles = rigidbody_set
243 .soft_body_colliders(&colliders.colliders, entity)
244 .or_else(|| colliders.entity2collider.get(&entity).map(|h| vec![*h]));
245 if let Some(handles) = handles {
246 for handle in handles {
247 if let Some(co) = colliders.colliders.get_mut(handle) {
248 co.set_sensor(false);
249 }
250 }
251 break;
252 }
253 }
254 }
255
256 for entity in removed_colliders_disabled.read() {
257 if let Some((mut context, handle)) = find_context(&mut context_writer, |context| {
258 context.1.entity2collider.get(&entity).copied()
259 }) {
260 if let Some(co) = context.1.colliders.get_mut(handle) {
261 co.set_enabled(true);
262 }
263 }
264 }
265
266 for entity in removed_impulse_joints_disabled.read() {
268 if let Ok(mut joint) = impulse_joints.get_mut(entity) {
269 joint.set_changed();
270 }
271 }
272
273 for entity in removed_rigid_body_disabled.read() {
274 if let Some(((_, _, _, mut rigidbody_set), handle)) =
275 find_context(&mut context_writer, |res| {
276 res.3.entity2body.get(&entity).copied()
277 })
278 {
279 if let Some(rb) = rigidbody_set.bodies.get_mut(handle) {
280 rb.set_enabled(true);
281 }
282 }
283 }
284}
285
286type RemovedComponent<'w, 's, T> = (RemovedComponents<'w, 's, T>, Query<'w, 's, (), With<T>>);
289
290pub fn reset_removed_rigid_body_components(
293 mut rigid_body_sets: Query<&mut RapierRigidBodySet>,
294 (mut removed_forces, mut removed_damping, mut removed_gravity_scale, mut removed_dominance): (
295 RemovedComponent<ExternalForce>,
296 RemovedComponent<Damping>,
297 RemovedComponent<GravityScale>,
298 RemovedComponent<Dominance>,
299 ),
300 (mut removed_ccd, mut removed_soft_ccd, mut removed_fast_rotation): (
301 RemovedComponent<Ccd>,
302 RemovedComponent<SoftCcd>,
303 RemovedComponent<AllowFastRotation>,
304 ),
305 (mut removed_locked_axes, mut removed_mass_props, mut removed_sleeping): (
306 RemovedComponent<LockedAxes>,
307 RemovedComponent<AdditionalMassProperties>,
308 RemovedComponent<Sleeping>,
309 ),
310 (mut removed_solver_iters, mut removed_pgs_iters): (
311 RemovedComponent<AdditionalSolverIterations>,
312 RemovedComponent<AdditionalPgsIterations>,
313 ),
314 #[cfg(feature = "dim3")] mut removed_gyroscopic_forces: RemovedComponent<GyroscopicForces>,
315 mut mass_modified: MessageWriter<MassModifiedEvent>,
316) {
317 let sets = &mut rigid_body_sets;
318 reset_removed(&mut removed_forces, sets, |_, rb| {
319 rb.reset_forces(true);
320 rb.reset_torques(true);
321 });
322 reset_removed(&mut removed_damping, sets, |_, rb| {
323 let default = Damping::default();
324 rb.set_linear_damping(default.linear_damping);
325 rb.set_angular_damping(default.angular_damping);
326 });
327 reset_removed(&mut removed_gravity_scale, sets, |_, rb| {
328 rb.set_gravity_scale(GravityScale::default().0, true);
329 });
330 reset_removed(&mut removed_dominance, sets, |_, rb| {
331 rb.set_dominance_group(Dominance::default().groups);
332 });
333 reset_removed(&mut removed_ccd, sets, |_, rb| {
334 rb.enable_ccd(Ccd::default().enabled);
335 });
336 reset_removed(&mut removed_soft_ccd, sets, |_, rb| {
337 rb.set_soft_ccd_prediction(SoftCcd::default().prediction);
338 });
339 reset_removed(&mut removed_fast_rotation, sets, |_, rb| {
340 rb.set_allow_fast_rotation(false);
341 });
342 reset_removed(&mut removed_locked_axes, sets, |_, rb| {
343 rb.set_locked_axes(LockedAxes::default().into(), true);
344 });
345 reset_removed(&mut removed_mass_props, sets, |entity, rb| {
346 rb.set_additional_mass_properties(MassProperties::default().into_rapier(), true);
347 mass_modified.write(entity.into());
348 });
349 reset_removed(&mut removed_sleeping, sets, |_, rb| {
350 let default = Sleeping::default();
351 let activation = rb.activation_mut();
352 activation.normalized_linear_threshold = default.normalized_linear_threshold;
353 activation.angular_threshold = default.angular_threshold;
354 activation.time_until_sleep = default.time_until_sleep;
355 });
356 reset_removed(&mut removed_solver_iters, sets, |_, rb| {
357 rb.set_additional_solver_iterations(AdditionalSolverIterations::default().0);
358 });
359 reset_removed(&mut removed_pgs_iters, sets, |_, rb| {
360 rb.set_additional_pgs_iterations(AdditionalPgsIterations::default().0);
361 });
362 #[cfg(feature = "dim3")]
363 reset_removed(&mut removed_gyroscopic_forces, sets, |_, rb| {
364 rb.enable_gyroscopic_forces(GyroscopicForces::default().enabled);
365 });
366}
367
368fn reset_removed<T: Component>(
371 (removed, still_present): &mut RemovedComponent<T>,
372 rigid_body_sets: &mut Query<&mut RapierRigidBodySet>,
373 mut reset: impl FnMut(Entity, &mut rapier::dynamics::RigidBody),
374) {
375 for entity in removed.read() {
376 if still_present.contains(entity) {
377 continue;
378 }
379
380 for mut rigid_body_set in rigid_body_sets.iter_mut() {
381 if let Some(handle) = rigid_body_set.entity2body.get(&entity).copied() {
382 if let Some(rb) = rigid_body_set.bodies.get_mut(handle) {
383 reset(entity, rb);
384 }
385 break;
386 }
387 }
388 }
389}
390
391pub fn reset_removed_collider_components(
396 mut contexts: Query<(&mut RapierContextColliders, &RapierRigidBodySet)>,
397 soft_bodies: Query<&SoftBody>,
398 (mut removed_friction, mut removed_restitution, mut removed_contact_skin): (
399 RemovedComponent<Friction>,
400 RemovedComponent<Restitution>,
401 RemovedComponent<ContactSkin>,
402 ),
403 (mut removed_collision_groups, mut removed_solver_groups): (
404 RemovedComponent<CollisionGroups>,
405 RemovedComponent<SolverGroups>,
406 ),
407 (mut removed_events, mut removed_hooks, mut removed_collision_types): (
408 RemovedComponent<ActiveEvents>,
409 RemovedComponent<ActiveHooks>,
410 RemovedComponent<ActiveCollisionTypes>,
411 ),
412 (mut removed_force_threshold, mut removed_mass_props): (
413 RemovedComponent<ContactForceEventThreshold>,
414 RemovedComponent<ColliderMassProperties>,
415 ),
416 mut read_mass_props: Query<&mut ReadColliderMassProperties>,
417 mut mass_modified: MessageWriter<MassModifiedEvent>,
418) {
419 let ctxts = &mut contexts;
420 let sbs = &soft_bodies;
421 reset_removed_collider(&mut removed_friction, ctxts, sbs, |_, co, _, defaults| {
422 co.set_friction(defaults.friction);
423 co.set_friction_combine_rule(defaults.friction_combine_rule);
424 });
425 reset_removed_collider(
426 &mut removed_restitution,
427 ctxts,
428 sbs,
429 |_, co, _, defaults| {
430 co.set_restitution(defaults.restitution);
431 co.set_restitution_combine_rule(defaults.restitution_combine_rule);
432 },
433 );
434 reset_removed_collider(
435 &mut removed_contact_skin,
436 ctxts,
437 sbs,
438 |entity, co, rigid_body_set, defaults| {
439 let skin = rigid_body_set
441 .soft_body(entity)
442 .map_or(defaults.contact_skin, |sb| sb.particle_radius());
443 co.set_contact_skin(skin);
444 },
445 );
446 reset_removed_collider(
447 &mut removed_collision_groups,
448 ctxts,
449 sbs,
450 |_, co, _, defaults| {
451 co.set_collision_groups(defaults.collision_groups);
452 },
453 );
454 reset_removed_collider(
455 &mut removed_solver_groups,
456 ctxts,
457 sbs,
458 |_, co, _, defaults| {
459 co.set_solver_groups(defaults.solver_groups);
460 },
461 );
462 reset_removed_collider(&mut removed_events, ctxts, sbs, |_, co, _, defaults| {
463 co.set_active_events(defaults.active_events);
464 });
465 reset_removed_collider(&mut removed_hooks, ctxts, sbs, |_, co, _, defaults| {
466 co.set_active_hooks(defaults.active_hooks);
467 });
468 reset_removed_collider(
469 &mut removed_collision_types,
470 ctxts,
471 sbs,
472 |_, co, _, defaults| {
473 co.set_active_collision_types(defaults.active_collision_types);
474 },
475 );
476 reset_removed_collider(
477 &mut removed_force_threshold,
478 ctxts,
479 sbs,
480 |_, co, _, defaults| {
481 co.set_contact_force_event_threshold(defaults.contact_force_event_threshold);
482 },
483 );
484 reset_removed_collider(
485 &mut removed_mass_props,
486 ctxts,
487 sbs,
488 |entity, co, rigid_body_set, _| {
489 if rigid_body_set.soft_body(entity).is_some() {
491 return;
492 }
493 co.set_density(rapier::geometry::ColliderBuilder::default_density());
494
495 if let Ok(mut read_mass_props) = read_mass_props.get_mut(entity) {
496 read_mass_props.set_if_neq(ReadColliderMassProperties::from_rapier(co));
497 }
498
499 if let Some(body_entity) = co
500 .parent()
501 .and_then(|h| rigid_body_set.rigid_body_entity(h))
502 {
503 mass_modified.write(body_entity.into());
504 }
505 },
506 );
507}
508
509fn reset_removed_collider<T: Component>(
516 (removed, still_present): &mut RemovedComponent<T>,
517 contexts: &mut Query<(&mut RapierContextColliders, &RapierRigidBodySet)>,
518 soft_bodies: &Query<&SoftBody>,
519 mut reset: impl FnMut(
520 Entity,
521 &mut rapier::geometry::Collider,
522 &RapierRigidBodySet,
523 &rapier::geometry::ColliderBuilder,
524 ),
525) {
526 let defaults = rapier::geometry::ColliderBuilder::default();
527 for entity in removed.read() {
528 if still_present.contains(entity) {
529 continue;
530 }
531
532 for (mut context_colliders, rigid_body_set) in contexts.iter_mut() {
533 if let Some(handles) =
534 rigid_body_set.soft_body_colliders(&context_colliders.colliders, entity)
535 {
536 let template = soft_bodies
537 .get(entity)
538 .ok()
539 .and_then(|sb| sb.builder.collider_template.as_ref())
540 .unwrap_or(&defaults);
541 for handle in handles {
542 if let Some(co) = context_colliders.colliders.get_mut(handle) {
543 reset(entity, co, rigid_body_set, template);
544 }
545 }
546 break;
547 }
548 if let Some(handle) = context_colliders.entity2collider.get(&entity).copied() {
549 if let Some(co) = context_colliders.colliders.get_mut(handle) {
550 reset(entity, co, rigid_body_set, &defaults);
551 }
552 break;
553 }
554 }
555 }
556}
557
558fn find_context<'a, TReturn, TQueryParams: IterQueryData>(
559 context_writer: &'a mut Query<TQueryParams>,
560 item_finder: impl Fn(&mut TQueryParams::Item<'_, '_>) -> Option<TReturn>,
561) -> Option<(TQueryParams::Item<'a, 'a>, TReturn)> {
562 let ret: Option<(TQueryParams::Item<'_, '_>, TReturn)> = context_writer
563 .iter_mut()
564 .find_map(|mut context| item_finder(&mut context).map(|handle| (context, handle)));
565 ret
566}