Closed kshaa closed 1 year ago
Finally got time to check this out again. I just configured bevy_ggrs
to rollback all of my entities, including their physics components and it seems to have done the job just fine. Also had to setup enhanced determinism and fixed timestep.
The RapierContext
isn't being rolled back, but it doesn't seem to result in problems. Maybe this isn't perfect, but works for me, so will close this ticket.
For context I'll add some code if anyone else tries this. It's a bit all over the place, but I hope the gist of it makes sense.
Step 0. Configure enhanced timestep in cargo features Step 1. Define timestep as fixed in rapier config
pub fn rapier_config(&self) -> RapierConfiguration {
RapierConfiguration {
timestep_mode: TimestepMode::Fixed {
dt: 1.0 / f32::from(self.fps),
substeps: 1
},
..RapierConfiguration::default()
}
}
Step 2. Insert Rapier config & plugin into app
game.insert_resource(config.rapier_config())
.add_plugin(
RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(config.pixels_per_meter)
.with_default_system_setup(false));
Step 3. Define your synchronized game logic for GGRS to run for every tick
let mut synchronized_stage = SystemStage::single_threaded();
synchronized_stage
.add_system(my_custom_system_which_adds_forces_based_on_ggrs_inputs)
.add_system_set(
RapierPhysicsPlugin::<NoUserData>::get_systems(PhysicsStages::SyncBackend))
.add_system_set(
RapierPhysicsPlugin::<NoUserData>::get_systems(PhysicsStages::StepSimulation))
.add_system_set(
RapierPhysicsPlugin::<NoUserData>::get_systems(PhysicsStages::Writeback))
.add_system_set(
RapierPhysicsPlugin::<NoUserData>::get_systems(PhysicsStages::DetectDespawn));
Step 4. Setup GGRS
fn build_network(game: &mut App, config: &GameConfig, synchronized_stage: SystemStage, session: P2PSession<GGRSConfig>) {
// Setup GGRS
GGRSPlugin::<GGRSConfig>::new()
// define frequency of rollback game logic update
.with_update_frequency(usize::from(config.fps))
// define system that returns inputs given a player handle, so GGRS can send the inputs around
.with_input_system(synchronized_input)
// register types of components AND resources you want to be rolled back
.register_rollback_component::<Transform>()
.register_rollback_component::<Velocity>()
.register_rollback_component::<ExternalForce>()
.register_rollback_component::<ExternalImpulse>()
// .register_rollback_resource::<RapierContext>() // TODO maybe :shrugs:
// these systems will be executed as part of the advance frame update
.with_rollback_schedule(
Schedule::default().with_stage(
"rollback_default",
synchronized_stage
),
)
// make it happen in the bevy app
.build(game);
// Add session to game
game.insert_resource(Session::P2PSession(session));
Turns out I also had to do some copying magic w/ the rapier context:
unserialized.islands = bincode::deserialize(&serialized.as_ref().islands).unwrap();
unserialized.broad_phase = bincode::deserialize(&serialized.as_ref().broad_phase).unwrap();
unserialized.narrow_phase = bincode::deserialize(&serialized.as_ref().narrow_phase).unwrap();
unserialized.bodies = bincode::deserialize(&serialized.as_ref().bodies).unwrap();
unserialized.colliders = bincode::deserialize(&serialized.as_ref().colliders).unwrap();
unserialized.impulse_joints = bincode::deserialize(&serialized.as_ref().impulse_joints).unwrap();
unserialized.multibody_joints = bincode::deserialize(&serialized.as_ref().multibody_joints).unwrap();
unserialized.ccd_solver = bincode::deserialize(&serialized.as_ref().ccd_solver).unwrap();
unserialized.query_pipeline = bincode::deserialize(&serialized.as_ref().query_pipeline).unwrap();
unserialized.integration_parameters = bincode::deserialize(&serialized.as_ref().integration_parameters).unwrap();
unserialized.pipeline = PhysicsPipeline::new();
Essentially had to store (deserialize) and then load (serialize) each serializable engine context piece on each frame. Looks fairly deterministic. Not sure if it is. But perhaps it's helpful to someone else too. Sorry if this is spam.
If anyone wants the full code from my attempt to integrate Bevy, GGRS and Rapier, here it is - https://github.com/kshaa/zoop.
Notes:
I'd like to use
bevy_rapier
in a networked game which uses state rollback. I was planning to usebevy_ggrs
for that, but in order to rollback the whole physics state i.e.RapierContext
bevy_ggrs
requires the context to haveReflect
:Is there any reason why
RapierContext
resource doesn't supportReflect
?