From 821cde98b7868472041e64d5f67cc2dea05198a1 Mon Sep 17 00:00:00 2001 From: Thierry Berger Date: Wed, 4 Dec 2024 17:22:52 +0100 Subject: [PATCH] Fix sync_removals with low physics fixed rate (#600) * fix sync_removals with low physics fixed rate * simplify test_sync_removal --- src/plugin/plugin.rs | 86 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/src/plugin/plugin.rs b/src/plugin/plugin.rs index 48effac6..00328a79 100644 --- a/src/plugin/plugin.rs +++ b/src/plugin/plugin.rs @@ -247,6 +247,10 @@ where .chain(), ); + // These *must* be in the main schedule currently so that they do not miss events. + // See test `test_sync_removal` for an example of this. + app.add_systems(PostUpdate, (systems::sync_removals,)); + // Add each set as necessary if self.default_system_setup { app.configure_sets( @@ -498,4 +502,86 @@ mod test { )); } } + + #[test] + pub fn test_sync_removal() { + return main(); + + use bevy::prelude::*; + + fn run_test(app: &mut App) { + app.insert_resource(TimeUpdateStrategy::ManualDuration( + std::time::Duration::from_secs_f32(1f32 / 60f32), + )); + app.insert_resource(Time::::from_hz(20.0)); + + app.add_systems(Startup, setup_physics); + app.add_systems(Update, remove_rapier_entity); + app.add_systems(FixedUpdate, || println!("Fixed Update")); + app.add_systems(Update, || println!("Update")); + // startup + app.update(); + // normal updates starting + // render only + app.update(); + app.update(); + // render + physics + app.update(); + + let context = app + .world_mut() + .query::<&RapierContext>() + .get_single(&app.world()) + .unwrap(); + assert_eq!(context.entity2body.len(), 1); + + // render only + remove entities + app.update(); + // Fixed Update hasnĀ“t run yet, so it's a risk of not having caught the bevy removed event, which will be cleaned next frame. + + let context = app + .world_mut() + .query::<&RapierContext>() + .get_single(&app.world()) + .unwrap(); + + println!("{:?}", &context.entity2body); + assert_eq!(context.entity2body.len(), 0); + } + + fn main() { + let mut app = App::new(); + app.add_plugins(( + HeadlessRenderPlugin, + TransformPlugin, + TimePlugin, + RapierPhysicsPlugin::::default().in_fixed_schedule(), + )); + run_test(&mut app); + } + + pub fn setup_physics(mut commands: Commands) { + commands.spawn(( + TransformBundle::from(Transform::from_xyz(0.0, 13.0, 0.0)), + RigidBody::Dynamic, + cuboid(0.5, 0.5, 0.5), + TestMarker, + )); + println!("spawned rapier entity"); + } + pub fn remove_rapier_entity( + mut commands: Commands, + to_remove: Query>, + mut counter: Local, + ) { + *counter += 1; + if *counter != 5 { + return; + } + println!("removing rapier entity"); + for e in &to_remove { + commands.entity(e).despawn(); + } + } + } }