From 7a4ba5ef2d81283cbb4cd046b0f70fd8e333e2c7 Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Wed, 26 Jun 2024 15:22:55 +0200 Subject: [PATCH] better support for multi world --- src/pipeline/events.rs | 2 +- src/plugin/configuration.rs | 3 +- src/plugin/context/systemparams.rs | 49 ++++++--- src/plugin/systems/character_controller.rs | 10 +- src/plugin/systems/collider.rs | 23 ++-- src/plugin/systems/joint.rs | 121 +++++++++++---------- src/plugin/systems/mod.rs | 15 ++- src/plugin/systems/remove.rs | 3 - src/plugin/systems/rigid_body.rs | 7 +- src/plugin/systems/writeback.rs | 15 ++- src/render/mod.rs | 50 +++++---- 11 files changed, 160 insertions(+), 138 deletions(-) diff --git a/src/pipeline/events.rs b/src/pipeline/events.rs index 5adcf938..6742dfb6 100644 --- a/src/pipeline/events.rs +++ b/src/pipeline/events.rs @@ -1,5 +1,5 @@ use crate::math::{Real, Vect}; -use bevy::prelude::{Entity, Event, EventWriter}; +use bevy::prelude::{Entity, Event}; use rapier::dynamics::RigidBodySet; use rapier::geometry::{ ColliderHandle, ColliderSet, CollisionEvent as RapierCollisionEvent, CollisionEventFlags, diff --git a/src/plugin/configuration.rs b/src/plugin/configuration.rs index 84a747fa..f5179331 100644 --- a/src/plugin/configuration.rs +++ b/src/plugin/configuration.rs @@ -1,7 +1,6 @@ -use bevy::prelude::{default, Component, FromWorld, Resource, World}; +use bevy::prelude::{Component, Resource}; use crate::math::{Real, Vect}; -use crate::plugin::RapierContext; /// The different ways of adjusting the timestep length each frame. #[derive(Copy, Clone, Debug, PartialEq, Resource)] diff --git a/src/plugin/context/systemparams.rs b/src/plugin/context/systemparams.rs index f9f79a43..f9c0a646 100644 --- a/src/plugin/context/systemparams.rs +++ b/src/plugin/context/systemparams.rs @@ -1,7 +1,5 @@ use bevy::ecs::system::SystemParam; use bevy::prelude::*; -use rapier::dynamics::RigidBodyHandle; -use std::collections::HashMap; use std::ops::{Deref, DerefMut}; use super::{DefaultRapierContext, RapierContext, RapierContextEntityLink}; @@ -14,7 +12,7 @@ pub struct DefaultRapierContextAccess<'w, 's> { impl<'w, 's> DefaultRapierContextAccess<'w, 's> { /// Use this method if you only have one world. - pub fn single<'a>(&'_ self) -> &RapierContext { + pub fn single(&'_ self) -> &RapierContext { self.rapier_context.single() } } @@ -51,13 +49,25 @@ impl<'w, 's> DerefMut for DefaultRapierContextAccessMut<'w, 's> { /// Utility [`SystemParam`] to easily access any [`RapierContext`] immutably #[derive(SystemParam)] pub struct RapierContextAccess<'w, 's> { - rapier_context: Query<'w, 's, &'static RapierContext, With>, + rapier_context: Query<'w, 's, &'static RapierContext>, + rapier_context_link: Query<'w, 's, &'static RapierContextEntityLink>, } impl<'w, 's> RapierContextAccess<'w, 's> { - /// Use this method if you only have one world. - pub fn single<'a>(&'_ self) -> &RapierContext { - self.rapier_context.single() + pub fn link(&self, entity: Entity) -> &RapierContextEntityLink { + self.rapier_context_link + .get(entity) + .expect("RapierContextAccess.link called on an entity without RapierContextEntityLink.") + } + pub fn follow_link(&self, link: RapierContextEntityLink) -> &'_ RapierContext { + self.rapier_context + .get(link.0) + .expect("RapierContextEntityLink.0 refers to an entity without RapierContext.") + } + + pub fn context(&self, entity: Entity) -> &'_ RapierContext { + let context_link = self.link(entity); + self.follow_link(*context_link) } } @@ -72,21 +82,27 @@ impl<'w, 's> Deref for RapierContextAccess<'w, 's> { /// Utility [`SystemParam`] to easily access any [`RapierContext`] mutably #[derive(SystemParam)] pub struct RapierContextAccessMut<'w, 's> { - rapier_context: Query<'w, 's, &'static mut RapierContext>, - rapier_context_link: Query<'w, 's, &'static mut RapierContextEntityLink>, + pub rapier_context: Query<'w, 's, &'static mut RapierContext>, + pub rapier_context_link: Query<'w, 's, &'static RapierContextEntityLink>, } impl<'w, 's> RapierContextAccessMut<'w, 's> { - pub fn context(&mut self, entity: Entity) -> &'_ mut RapierContext { - let context_link = self - .rapier_context_link - .get(entity) - .expect("entity2body called on an entity without RapierContextEntityLink."); + pub fn link(&self, entity: Entity) -> &RapierContextEntityLink { + self.rapier_context_link.get(entity).expect( + "RapierContextAccessMut.link called on an entity without RapierContextEntityLink.", + ) + } + pub fn follow_link(&mut self, link: RapierContextEntityLink) -> &'_ mut RapierContext { self.rapier_context - .get_mut(context_link.0) - .expect("RapierContextEntityLink refers to an entity without RapierContext.") + .get_mut(link.0) + .expect("RapierContextEntityLink.0 refers to an entity without RapierContext.") .into_inner() } + + pub fn context(&mut self, entity: Entity) -> &'_ mut RapierContext { + let context_link = self.link(entity); + self.follow_link(*context_link) + } } pub fn try_retrieve_context<'a>( @@ -96,7 +112,6 @@ pub fn try_retrieve_context<'a>( link.map_or_else( || { let context_entity = context.iter().next().unwrap().0; - RapierContextEntityLink(context_entity); Err(context_entity) }, |link| Ok(link.0), diff --git a/src/plugin/systems/character_controller.rs b/src/plugin/systems/character_controller.rs index 5baaefd3..0fec5b50 100644 --- a/src/plugin/systems/character_controller.rs +++ b/src/plugin/systems/character_controller.rs @@ -1,8 +1,8 @@ use crate::control::CharacterCollision; use crate::dynamics::RapierRigidBodyHandle; use crate::geometry::RapierColliderHandle; -use crate::plugin::DefaultRapierContextAccessMut; use crate::plugin::RapierConfiguration; +use crate::plugin::RapierContextAccessMut; use crate::prelude::KinematicCharacterController; use crate::prelude::KinematicCharacterControllerOutput; use crate::utils; @@ -16,7 +16,7 @@ use rapier::pipeline::QueryFilter; pub fn update_character_controls( mut commands: Commands, config: Query<&RapierConfiguration>, - mut context: DefaultRapierContextAccessMut, + mut context_access: RapierContextAccessMut, mut character_controllers: Query<( Entity, &mut KinematicCharacterController, @@ -27,12 +27,12 @@ pub fn update_character_controls( )>, mut transforms: Query<&mut Transform>, ) { - let context = &mut *context; - let config = &*config.single(); - for (entity, mut controller, output, collider_handle, body_handle, glob_transform) in character_controllers.iter_mut() { + let link = *context_access.link(entity); + let context = context_access.follow_link(link); + let config = config.get(link.0).unwrap(); if let (Some(raw_controller), Some(translation)) = (controller.to_raw(), controller.translation) { diff --git a/src/plugin/systems/collider.rs b/src/plugin/systems/collider.rs index 1e5a336b..4ee87d52 100644 --- a/src/plugin/systems/collider.rs +++ b/src/plugin/systems/collider.rs @@ -2,9 +2,7 @@ use crate::dynamics::ReadMassProperties; use crate::geometry::Collider; use crate::plugin::context::systemparams::try_retrieve_context; use crate::plugin::context::RapierContextEntityLink; -use crate::plugin::{ - DefaultRapierContextAccessMut, RapierConfiguration, RapierContext, RapierContextAccessMut, -}; +use crate::plugin::{RapierConfiguration, RapierContext, RapierContextAccessMut}; use crate::prelude::{ ActiveCollisionTypes, ActiveEvents, ActiveHooks, ColliderDisabled, ColliderMassProperties, ColliderScale, CollidingEntities, CollisionEvent, CollisionGroups, ContactForceEventThreshold, @@ -310,8 +308,6 @@ pub fn init_colliders( parent_query: Query<&Parent>, transform_query: Query<&Transform>, ) { - let config = &*config.single(); - for ( ( (entity, context_link), @@ -332,6 +328,15 @@ pub fn init_colliders( global_transform, ) in colliders.iter() { + let context_entity = + try_retrieve_context(context_link, &context).unwrap_or_else(|context_entity| { + commands + .entity(entity) + .insert(RapierContextEntityLink(context_entity)); + context_entity + }); + let context = &mut *context.get_mut(context_entity).unwrap().1; + let config = config.get(context_entity).unwrap(); 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()); @@ -388,14 +393,6 @@ pub fn init_colliders( if let Some(threshold) = contact_force_event_threshold { builder = builder.contact_force_event_threshold(threshold.0); } - let context_entity = - try_retrieve_context(context_link, &context).unwrap_or_else(|context_entity| { - commands - .entity(entity) - .insert(RapierContextEntityLink(context_entity)); - context_entity - }); - let context = &mut *context.get_mut(context_entity).unwrap().1; let body_entity = entity; let (body_handle, child_transform) = collider_offset(entity, context, &parent_query, &transform_query); diff --git a/src/plugin/systems/joint.rs b/src/plugin/systems/joint.rs index caacf5ac..d08586ec 100644 --- a/src/plugin/systems/joint.rs +++ b/src/plugin/systems/joint.rs @@ -2,61 +2,59 @@ use crate::dynamics::ImpulseJoint; use crate::dynamics::MultibodyJoint; use crate::dynamics::RapierImpulseJointHandle; use crate::dynamics::RapierMultibodyJointHandle; -use crate::plugin::RapierContext; +use crate::plugin::context::RapierContextEntityLink; +use crate::plugin::RapierContextAccessMut; use bevy::prelude::*; /// System responsible for creating new Rapier joints from the related `bevy_rapier` components. pub fn init_joints( mut commands: Commands, - mut context: Query<&mut RapierContext>, + mut context: RapierContextAccessMut, impulse_joints: Query<(Entity, &ImpulseJoint), Without>, multibody_joints: Query<(Entity, &MultibodyJoint), Without>, parent_query: Query<&Parent>, ) { - for mut context in context.iter_mut() { - let context = &mut *context; - - for (entity, joint) in impulse_joints.iter() { - let mut target = None; - let mut body_entity = entity; - while target.is_none() { - target = context.entity2body.get(&body_entity).copied(); - if let Ok(parent_entity) = parent_query.get(body_entity) { - body_entity = parent_entity.get(); - } else { - break; - } + for (entity, joint) in impulse_joints.iter() { + let context = context.context(entity); + let mut target = None; + let mut body_entity = entity; + while target.is_none() { + target = context.entity2body.get(&body_entity).copied(); + if let Ok(parent_entity) = parent_query.get(body_entity) { + body_entity = parent_entity.get(); + } else { + break; } + } - if let (Some(target), Some(source)) = (target, context.entity2body.get(&joint.parent)) { - let handle = - context - .impulse_joints - .insert(*source, target, joint.data.into_rapier(), true); - commands - .entity(entity) - .insert(RapierImpulseJointHandle(handle)); - context.entity2impulse_joint.insert(entity, handle); - } + if let (Some(target), Some(source)) = (target, context.entity2body.get(&joint.parent)) { + let handle = + context + .impulse_joints + .insert(*source, target, joint.data.into_rapier(), true); + commands + .entity(entity) + .insert(RapierImpulseJointHandle(handle)); + context.entity2impulse_joint.insert(entity, handle); } + } - for (entity, joint) in multibody_joints.iter() { - let target = context.entity2body.get(&entity); + for (entity, joint) in multibody_joints.iter() { + let context = context.context(entity); + let target = context.entity2body.get(&entity); - if let (Some(target), Some(source)) = (target, context.entity2body.get(&joint.parent)) { - if let Some(handle) = context.multibody_joints.insert( - *source, - *target, - joint.data.into_rapier(), - true, - ) { - commands - .entity(entity) - .insert(RapierMultibodyJointHandle(handle)); - context.entity2multibody_joint.insert(entity, handle); - } else { - error!("Failed to create multibody joint: loop detected.") - } + if let (Some(target), Some(source)) = (target, context.entity2body.get(&joint.parent)) { + if let Some(handle) = + context + .multibody_joints + .insert(*source, *target, joint.data.into_rapier(), true) + { + commands + .entity(entity) + .insert(RapierMultibodyJointHandle(handle)); + context.entity2multibody_joint.insert(entity, handle); + } else { + error!("Failed to create multibody joint: loop detected.") } } } @@ -64,32 +62,39 @@ pub fn init_joints( /// System responsible for applying changes the user made to a joint component. pub fn apply_joint_user_changes( - mut context: Query<&mut RapierContext>, + mut context: RapierContextAccessMut, changed_impulse_joints: Query< - (&RapierImpulseJointHandle, &ImpulseJoint), + ( + &RapierContextEntityLink, + &RapierImpulseJointHandle, + &ImpulseJoint, + ), Changed, >, changed_multibody_joints: Query< - (&RapierMultibodyJointHandle, &MultibodyJoint), + ( + &RapierContextEntityLink, + &RapierMultibodyJointHandle, + &MultibodyJoint, + ), Changed, >, ) { - for mut context in context.iter_mut() { - let context = &mut *context; - // TODO: right now, we only support propagating changes made to the joint data. - // Re-parenting the joint isn’t supported yet. - for (handle, changed_joint) in changed_impulse_joints.iter() { - if let Some(joint) = context.impulse_joints.get_mut(handle.0) { - joint.data = changed_joint.data.into_rapier(); - } + // 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.follow_link(*link); + if let Some(joint) = context.impulse_joints.get_mut(handle.0) { + joint.data = changed_joint.data.into_rapier(); } + } - for (handle, changed_joint) in changed_multibody_joints.iter() { - // 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) { - link.joint.data = changed_joint.data.into_rapier(); - } + for (link, handle, changed_joint) in changed_multibody_joints.iter() { + let context = context.follow_link(*link); + // 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) { + link.joint.data = changed_joint.data.into_rapier(); } } } diff --git a/src/plugin/systems/mod.rs b/src/plugin/systems/mod.rs index cc1cbe48..d542b319 100644 --- a/src/plugin/systems/mod.rs +++ b/src/plugin/systems/mod.rs @@ -25,12 +25,14 @@ use bevy::prelude::*; /// System responsible for advancing the physics simulation, and updating the internal state /// for scene queries. pub fn step_simulation( - mut context: Query<&mut RapierContext>, + mut context: Query<( + &mut RapierContext, + &RapierConfiguration, + &mut SimulationToRenderTime, + )>, timestep_mode: Res, - config: Query<&RapierConfiguration>, hooks: StaticSystemParam, time: Res