diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f966b503..d9b2364f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -32,7 +32,7 @@ jobs: with: prefix-key: ${{ env.RUST_CACHE_KEY }} - name: Cargo doc - run: cargo doc + run: cargo doc --no-deps test: runs-on: ubuntu-latest env: @@ -72,6 +72,6 @@ jobs: with: prefix-key: ${{ env.RUST_CACHE_KEY }} - name: Clippy bevy_rapier2d - run: cd bevy_rapier2d && cargo clippy --verbose --features wasm-bindgen,bevy/webgl2 --target wasm32-unknown-unknown + run: cd bevy_rapier2d && cargo clippy --verbose --features bevy/webgl2 --target wasm32-unknown-unknown - name: Clippy bevy_rapier3d - run: cd bevy_rapier3d && cargo clippy --verbose --features wasm-bindgen,bevy/webgl2 --target wasm32-unknown-unknown + run: cd bevy_rapier3d && cargo clippy --verbose --features bevy/webgl2 --target wasm32-unknown-unknown diff --git a/CHANGELOG.md b/CHANGELOG.md index b6c9efdb..cc36e1fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,13 +4,19 @@ ### Modified +- Update from rapier `0.22` to rapier `0.23`, + see [rapier's changelog](https://github.com/dimforge/rapier/blob/master/CHANGELOG.md). +- `Collider::trimesh` and `Collider::trimesh_with_flags` now return a `Result`. +- Under the feature `async-collider`, The `RapierPhysicsPlugin` now adds + `AssetPlugin`, `MeshPlugin` and `ScenePlugin` if these were not added, to circumvent a runtime crash + over missing required resources. - `RapierContext` has been split in multiple `Component`s: - - `RapierContextColliders` - - `RapierContextJoints` - - `RapierContextSimulation` - - `RapierRigidBodySet` -- Renamed `DefaultReadRapierContext` and `DefaultWriteRapierContext`. - - Use `ReadRapierContext` and its associated `single()` method. + - `RapierContextColliders` + - `RapierContextJoints` + - `RapierContextSimulation` + - `RapierRigidBodySet` +- Renamed `DefaultReadRapierContext` to `ReadRapierContext` and `DefaultWriteRapierContext` to `WriteRapierContext`. + They have a new `bevy::QueryFilter` type parameter, defaulting to `With`. ## v0.28.0 (09 December 2024) diff --git a/bevy_rapier2d/Cargo.toml b/bevy_rapier2d/Cargo.toml index 4a626709..b4d1610e 100644 --- a/bevy_rapier2d/Cargo.toml +++ b/bevy_rapier2d/Cargo.toml @@ -45,16 +45,20 @@ rapier-debug-render = ["rapier2d/debug-render"] parallel = ["rapier2d/parallel"] simd-stable = ["rapier2d/simd-stable"] simd-nightly = ["rapier2d/simd-nightly"] -wasm-bindgen = ["rapier2d/wasm-bindgen"] serde-serialize = ["rapier2d/serde-serialize", "bevy/serialize", "serde"] enhanced-determinism = ["rapier2d/enhanced-determinism"] headless = [] -async-collider = ["bevy/bevy_asset", "bevy/bevy_scene", "bevy/bevy_render"] +async-collider = [ + "bevy/bevy_asset", + "bevy/bevy_scene", + "bevy/bevy_render", + "bevy/bevy_image", +] [dependencies] bevy = { version = "0.15", default-features = false } nalgebra = { version = "0.33", features = ["convert-glam029"] } -rapier2d = "0.22" +rapier2d = "0.23" bitflags = "2.4" log = "0.4" serde = { version = "1", features = ["derive"], optional = true } diff --git a/bevy_rapier3d/Cargo.toml b/bevy_rapier3d/Cargo.toml index b5d18c47..1f0aa2ef 100644 --- a/bevy_rapier3d/Cargo.toml +++ b/bevy_rapier3d/Cargo.toml @@ -46,16 +46,20 @@ rapier-debug-render = ["rapier3d/debug-render"] parallel = ["rapier3d/parallel"] simd-stable = ["rapier3d/simd-stable"] simd-nightly = ["rapier3d/simd-nightly"] -wasm-bindgen = ["rapier3d/wasm-bindgen"] serde-serialize = ["rapier3d/serde-serialize", "bevy/serialize", "serde"] enhanced-determinism = ["rapier3d/enhanced-determinism"] headless = [] -async-collider = ["bevy/bevy_asset", "bevy/bevy_scene", "bevy/bevy_render"] +async-collider = [ + "bevy/bevy_asset", + "bevy/bevy_scene", + "bevy/bevy_render", + "bevy/bevy_image", +] [dependencies] bevy = { version = "0.15", default-features = false } nalgebra = { version = "0.33", features = ["convert-glam029"] } -rapier3d = "0.22" +rapier3d = "0.23" bitflags = "2.4" log = "0.4" serde = { version = "1", features = ["derive"], optional = true } diff --git a/bevy_rapier3d/examples/static_trimesh3.rs b/bevy_rapier3d/examples/static_trimesh3.rs index 27fae6b5..5bc41382 100644 --- a/bevy_rapier3d/examples/static_trimesh3.rs +++ b/bevy_rapier3d/examples/static_trimesh3.rs @@ -55,7 +55,7 @@ pub fn setup_physics(mut commands: Commands, mut ball_state: ResMut) indices.push([2 * i + 2, 2 * i + 1, 2 * i + 3]); } - commands.spawn(Collider::trimesh(vertices, indices)); + commands.spawn(Collider::trimesh(vertices, indices).unwrap()); // Create a bowl with a cosine cross-section, // so that we can join the end of the ramp smoothly @@ -97,7 +97,7 @@ pub fn setup_physics(mut commands: Commands, mut ball_state: ResMut) -bowl_size.y / 2.0, bowl_size.z / 2.0 - ramp_size.z / 2.0, ), - Collider::trimesh(vertices, indices), + Collider::trimesh(vertices, indices).unwrap(), )); } diff --git a/bevy_rapier_benches3d/Cargo.toml b/bevy_rapier_benches3d/Cargo.toml index 80c325df..6b4689b4 100644 --- a/bevy_rapier_benches3d/Cargo.toml +++ b/bevy_rapier_benches3d/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -rapier3d = { features = ["profiler"], version = "0.22" } +rapier3d = { features = ["profiler"], version = "0.23" } bevy_rapier3d = { version = "0.28", path = "../bevy_rapier3d" } bevy = { version = "0.15", default-features = false } diff --git a/bevy_rapier_benches3d/src/lib.rs b/bevy_rapier_benches3d/src/lib.rs index bd6b16b8..ba24b105 100644 --- a/bevy_rapier_benches3d/src/lib.rs +++ b/bevy_rapier_benches3d/src/lib.rs @@ -25,21 +25,25 @@ pub fn custom_bencher(steps: usize, setup: impl Fn(&mut App)) { timer_full_update.start(); app.update(); timer_full_update.pause(); - let elapsed_time = timer_full_update.time() as f32; + let elapsed_time = timer_full_update.time().as_millis(); let rc = app .world_mut() .query::<&RapierContextSimulation>() .single(app.world()); - rapier_step_times.push(rc.pipeline.counters.step_time.time() as f32); + rapier_step_times.push(rc.pipeline.counters.step_time.time().as_millis() as f32); total_update_times.push(elapsed_time); } timer_total.pause(); - let average_total = total_update_times.iter().sum::() / total_update_times.len() as f32; + let average_total = total_update_times + .iter() + .map(|time| *time as f32) + .sum::() + / total_update_times.len() as f32; println!("average total time: {} ms", average_total); let average_rapier_step = rapier_step_times.iter().sum::() / rapier_step_times.len() as f32; println!("average rapier step time: {} ms", average_rapier_step); let average_rapier_overhead = average_total - average_rapier_step; println!("average bevy overhead: {} ms", average_rapier_overhead); - println!("total time: {} ms", timer_total.time()); + println!("total time: {} ms", timer_total.time().as_millis()); } diff --git a/src/geometry/collider_impl.rs b/src/geometry/collider_impl.rs index 88ead96e..c8892249 100644 --- a/src/geometry/collider_impl.rs +++ b/src/geometry/collider_impl.rs @@ -151,9 +151,12 @@ impl Collider { } /// Initializes a collider with a triangle mesh shape defined by its vertex and index buffers. - pub fn trimesh(vertices: Vec, indices: Vec<[u32; 3]>) -> Self { + pub fn trimesh( + vertices: Vec, + indices: Vec<[u32; 3]>, + ) -> Result { let vertices = vertices.into_iter().map(|v| v.into()).collect(); - SharedShape::trimesh(vertices, indices).into() + Ok(SharedShape::trimesh(vertices, indices)?.into()) } /// Initializes a collider with a triangle mesh shape defined by its vertex and index buffers, and flags @@ -162,9 +165,9 @@ impl Collider { vertices: Vec, indices: Vec<[u32; 3]>, flags: TriMeshFlags, - ) -> Self { + ) -> Result { let vertices = vertices.into_iter().map(|v| v.into()).collect(); - SharedShape::trimesh_with_flags(vertices, indices, flags).into() + Ok(SharedShape::trimesh_with_flags(vertices, indices, flags)?.into()) } /// Initializes a collider with a Bevy Mesh. @@ -175,9 +178,11 @@ impl Collider { let (vtx, idx) = extract_mesh_vertices_indices(mesh)?; match collider_shape { - ComputedColliderShape::TriMesh(flags) => { - Some(SharedShape::trimesh_with_flags(vtx, idx, *flags).into()) - } + ComputedColliderShape::TriMesh(flags) => Some( + SharedShape::trimesh_with_flags(vtx, idx, *flags) + .ok()? + .into(), + ), ComputedColliderShape::ConvexHull => { SharedShape::convex_hull(&vtx).map(|shape| shape.into()) } diff --git a/src/pipeline/events.rs b/src/pipeline/events.rs index ff3ccdb0..38df07c5 100644 --- a/src/pipeline/events.rs +++ b/src/pipeline/events.rs @@ -132,7 +132,6 @@ mod test { transform::{components::Transform, TransformPlugin}, MinimalPlugins, }; - use systems::tests::HeadlessRenderPlugin; use crate::{plugin::*, prelude::*}; @@ -180,6 +179,7 @@ mod test { app.insert_resource(TimeUpdateStrategy::ManualDuration( std::time::Duration::from_secs_f32(1f32 / 60f32), )); + app.finish(); // 2 seconds should be plenty of time for the cube to fall on the // lowest collider. for _ in 0..120 { @@ -201,7 +201,6 @@ mod test { fn main() { let mut app = App::new(); app.add_plugins(( - HeadlessRenderPlugin, TransformPlugin, TimePlugin, RapierPhysicsPlugin::::default(), @@ -236,7 +235,6 @@ mod test { pub fn spam_remove_rapier_entity_interpolated() { let mut app = App::new(); app.add_plugins(( - HeadlessRenderPlugin, MinimalPlugins, TransformPlugin, RapierPhysicsPlugin::::default(), @@ -253,6 +251,8 @@ mod test { std::time::Duration::from_secs_f32(1f32 / 60f32), )); + app.finish(); + for _ in 0..100 { app.update(); } diff --git a/src/plugin/plugin.rs b/src/plugin/plugin.rs index f16ef7bf..8ea0a18f 100644 --- a/src/plugin/plugin.rs +++ b/src/plugin/plugin.rs @@ -304,6 +304,22 @@ where } } } + + fn finish(&self, _app: &mut App) { + #[cfg(feature = "async-collider")] + { + use bevy::{asset::AssetPlugin, render::mesh::MeshPlugin, scene::ScenePlugin}; + if !_app.is_plugin_added::() { + _app.add_plugins(AssetPlugin::default()); + } + if !_app.is_plugin_added::() { + _app.add_plugins(MeshPlugin); + } + if !_app.is_plugin_added::() { + _app.add_plugins(ScenePlugin); + } + } + } } /// Specifies a default configuration for the default [`RapierContext`] @@ -374,7 +390,6 @@ mod test { time::{TimePlugin, TimeUpdateStrategy}, }; use rapier::{data::Index, dynamics::RigidBodyHandle}; - use systems::tests::HeadlessRenderPlugin; use crate::{plugin::context::*, plugin::*, prelude::*}; @@ -403,6 +418,8 @@ mod test { app.add_systems(Update, setup_physics); + app.finish(); + let mut stepping = Stepping::new(); app.update(); @@ -478,7 +495,6 @@ mod test { fn main() { let mut app = App::new(); app.add_plugins(( - HeadlessRenderPlugin, TransformPlugin, TimePlugin, RapierPhysicsPlugin::::default(), @@ -526,6 +542,7 @@ mod test { app.add_systems(Update, remove_rapier_entity); app.add_systems(FixedUpdate, || println!("Fixed Update")); app.add_systems(Update, || println!("Update")); + app.finish(); // startup app.update(); // normal updates starting @@ -559,7 +576,6 @@ mod test { fn main() { let mut app = App::new(); app.add_plugins(( - HeadlessRenderPlugin, TransformPlugin, TimePlugin, RapierPhysicsPlugin::::default().in_fixed_schedule(), diff --git a/src/plugin/systems/collider.rs b/src/plugin/systems/collider.rs index c371b556..c43fe5f6 100644 --- a/src/plugin/systems/collider.rs +++ b/src/plugin/systems/collider.rs @@ -589,11 +589,13 @@ pub mod test { #[cfg(all(feature = "dim3", feature = "async-collider"))] fn async_collider_initializes() { use super::*; - use crate::plugin::systems::tests::HeadlessRenderPlugin; + use bevy::{render::mesh::MeshPlugin, scene::ScenePlugin}; let mut app = App::new(); - app.add_plugins(HeadlessRenderPlugin) - .add_systems(Update, init_async_colliders); + app.add_plugins((AssetPlugin::default(), MeshPlugin, ScenePlugin)); + app.add_systems(Update, init_async_colliders); + + app.finish(); let mut meshes = app.world_mut().resource_mut::>(); let cube = meshes.add(Cuboid::default()); @@ -620,11 +622,11 @@ pub mod test { #[cfg(all(feature = "dim3", feature = "async-collider"))] fn async_scene_collider_initializes() { use super::*; - use crate::plugin::systems::tests::HeadlessRenderPlugin; + use bevy::{render::mesh::MeshPlugin, scene::ScenePlugin}; let mut app = App::new(); - app.add_plugins(HeadlessRenderPlugin) - .add_systems(PostUpdate, init_async_scene_colliders); + app.add_plugins((AssetPlugin::default(), MeshPlugin, ScenePlugin)); + app.add_systems(PostUpdate, init_async_scene_colliders); let mut meshes = app.world_mut().resource_mut::>(); let cube_handle = meshes.add(Cuboid::default()); diff --git a/src/plugin/systems/joint.rs b/src/plugin/systems/joint.rs index c62b7774..9bd364b5 100644 --- a/src/plugin/systems/joint.rs +++ b/src/plugin/systems/joint.rs @@ -138,7 +138,7 @@ pub fn apply_joint_user_changes( // Re-parenting the joint isn’t supported yet. for (link, handle, changed_joint) in changed_impulse_joints.iter() { let mut context = context.get_mut(link.0).expect(RAPIER_CONTEXT_EXPECT_ERROR); - if let Some(joint) = context.impulse_joints.get_mut(handle.0) { + if let Some(joint) = context.impulse_joints.get_mut(handle.0, false) { joint.data = changed_joint.data.as_ref().into_rapier(); } } diff --git a/src/plugin/systems/mod.rs b/src/plugin/systems/mod.rs index 420876f4..ef2d03bf 100644 --- a/src/plugin/systems/mod.rs +++ b/src/plugin/systems/mod.rs @@ -93,16 +93,7 @@ pub fn step_simulation( #[cfg(test)] #[allow(missing_docs)] pub mod tests { - use bevy::{ - asset::AssetPlugin, - ecs::event::Events, - render::{ - settings::{RenderCreation, WgpuSettings}, - RenderPlugin, - }, - scene::ScenePlugin, - time::TimePlugin, - }; + use bevy::{ecs::event::Events, time::TimePlugin}; use rapier::geometry::CollisionEventFlags; use std::f32::consts::PI; @@ -203,11 +194,11 @@ pub mod tests { fn transform_propagation() { let mut app = App::new(); app.add_plugins(( - HeadlessRenderPlugin, TransformPlugin, TimePlugin, RapierPhysicsPlugin::::default(), )); + app.finish(); let zero = (Transform::default(), Transform::default()); @@ -260,11 +251,11 @@ pub mod tests { fn transform_propagation2() { let mut app = App::new(); app.add_plugins(( - HeadlessRenderPlugin, TransformPlugin, TimePlugin, RapierPhysicsPlugin::::default(), )); + app.finish(); let zero = (Transform::default(), Transform::default()); @@ -342,24 +333,4 @@ pub mod tests { approx::assert_relative_eq!(body_transform.scale, child_transform.scale,); } } - - // Allows run tests for systems containing rendering related things without GPU - pub struct HeadlessRenderPlugin; - - impl Plugin for HeadlessRenderPlugin { - fn build(&self, app: &mut App) { - app.add_plugins(( - AssetPlugin::default(), - ScenePlugin, - RenderPlugin { - render_creation: RenderCreation::Automatic(WgpuSettings { - backends: None, - ..Default::default() - }), - ..Default::default() - }, - ImagePlugin::default(), - )); - } - } } diff --git a/src/plugin/systems/multiple_rapier_contexts.rs b/src/plugin/systems/multiple_rapier_contexts.rs index b24bccb9..a266425d 100644 --- a/src/plugin/systems/multiple_rapier_contexts.rs +++ b/src/plugin/systems/multiple_rapier_contexts.rs @@ -130,7 +130,6 @@ fn bubble_down_context_change( #[cfg(test)] mod test { - use crate::plugin::systems::tests::HeadlessRenderPlugin; use crate::plugin::{ context::{RapierContextEntityLink, RapierContextSimulation}, NoUserData, PhysicsSet, RapierPhysicsPlugin, @@ -144,7 +143,6 @@ mod test { pub fn multi_context_hierarchy_update() { let mut app = App::new(); app.add_plugins(( - HeadlessRenderPlugin, TransformPlugin, TimePlugin, RapierPhysicsPlugin::::default(), @@ -159,6 +157,7 @@ mod test { app.insert_resource(TimeUpdateStrategy::ManualDuration( std::time::Duration::from_secs_f32(1f32 / 60f32), )); + app.finish(); app.update(); // Verify all rapier entities have a `RapierContextEntityLink`. let world = app.world_mut();