From 55a1a68fa0189b98ac604abe4f1106c19a14d943 Mon Sep 17 00:00:00 2001 From: Zicklag Date: Wed, 23 Nov 2022 11:12:46 -0600 Subject: [PATCH] Attempt to Fix Multiplayer Desync This is based on the guess that the desync came from the lack of determinism in the scenario when you grab an item while touching multiple items, and it isn't necessarily specified which one you pick up. --- src/player/state/states/idle.rs | 28 +++++++++++++++++----------- src/player/state/states/midair.rs | 28 +++++++++++++++++----------- src/player/state/states/walk.rs | 25 +++++++++++++------------ 3 files changed, 47 insertions(+), 34 deletions(-) diff --git a/src/player/state/states/idle.rs b/src/player/state/states/idle.rs index aa2e71c822..3a27674e40 100644 --- a/src/player/state/states/idle.rs +++ b/src/player/state/states/idle.rs @@ -26,7 +26,7 @@ pub fn player_state_transition( pub fn handle_player_state( mut commands: Commands, player_inputs: Res, - items: Query<(Option<&Parent>, &KinematicBody), (With, Without)>, + items: Query<(Option<&Parent>, &Rollback), With>, mut players: Query<( Entity, &PlayerState, @@ -62,16 +62,22 @@ pub fn handle_player_state( if control.grab_just_pressed { // If we don't have an item if !has_item { - // For each actor colliding with the player - 'colliders: for collider in collision_world.actor_collisions(player_ent) { - // If this is an item - if let Ok((.., item_body)) = items.get(collider) { - if !item_body.is_deactivated { - commands - .add(PlayerSetInventoryCommand::new(player_ent, Some(collider))); - break 'colliders; - } - } + let mut colliders = collision_world + // Get all things colliding with the player + .actor_collisions(player_ent) + .into_iter() + // Filter out anything not an item + .filter_map(|ent| items.get(ent).ok().map(|x| (ent, x))) + // Filter out any items that are being held by another player + .filter(|(_ent, (parent, _))| parent.is_none()) + .collect::>(); + + // Sort the items to provide deterministic item selection if we hare touching multiples + colliders.sort_by_key(|(_, (_, rollback))| rollback.id()); + + // Grab the first item we are touching + if let Some((item, _)) = colliders.get(0) { + commands.add(PlayerSetInventoryCommand::new(player_ent, Some(*item))); } // If we are already carrying an item diff --git a/src/player/state/states/midair.rs b/src/player/state/states/midair.rs index f633a141b1..1cb1f9ced9 100644 --- a/src/player/state/states/midair.rs +++ b/src/player/state/states/midair.rs @@ -19,7 +19,7 @@ pub fn player_state_transition(mut players: Query<(&mut PlayerState, &KinematicB pub fn handle_player_state( mut commands: Commands, player_inputs: Res, - items: Query<(Option<&Parent>, &KinematicBody), (With, Without)>, + items: Query<(Option<&Parent>, &Rollback), With>, mut players: Query<( Entity, &PlayerState, @@ -53,17 +53,23 @@ pub fn handle_player_state( // If we are grabbing if control.grab_just_pressed { - // If we don't have an item if !has_item { - // For each actor colliding with the player - 'colliders: for collider in collision_world.actor_collisions(player_ent) { - if let Ok((.., item_body)) = items.get(collider) { - if !item_body.is_deactivated { - commands - .add(PlayerSetInventoryCommand::new(player_ent, Some(collider))); - break 'colliders; - } - } + let mut colliders = collision_world + // Get all things colliding with the player + .actor_collisions(player_ent) + .into_iter() + // Filter out anything not an item + .filter_map(|ent| items.get(ent).ok().map(|x| (ent, x))) + // Filter out any items that are being held by another player + .filter(|(_ent, (parent, _))| parent.is_none()) + .collect::>(); + + // Sort the items to provide deterministic item selection if we hare touching multiples + colliders.sort_by_key(|(_, (_, rollback))| rollback.id()); + + // Grab the first item we are touching + if let Some((item, _)) = colliders.get(0) { + commands.add(PlayerSetInventoryCommand::new(player_ent, Some(*item))); } // If we are already carrying an item diff --git a/src/player/state/states/walk.rs b/src/player/state/states/walk.rs index 20a0627f80..5970474a50 100644 --- a/src/player/state/states/walk.rs +++ b/src/player/state/states/walk.rs @@ -27,7 +27,7 @@ pub fn player_state_transition( pub fn handle_player_state( mut commands: Commands, player_inputs: Res, - items: Query<(Option<&Parent>, &KinematicBody), (With, Without)>, + items: Query<(Option<&Parent>, &Rollback), With>, mut players: Query<( Entity, &PlayerState, @@ -63,17 +63,18 @@ pub fn handle_player_state( if control.grab_just_pressed { // If we don't have an item if !has_item { - // For each actor colliding with the player - 'colliders: for collider in collision_world.actor_collisions(player_ent) { - // If this is an item - if let Ok((.., item_body)) = items.get(collider) { - if !item_body.is_deactivated { - commands - .add(PlayerSetInventoryCommand::new(player_ent, Some(collider))); - break 'colliders; - } - } - } + let mut colliders = collision_world + // Get all things colliding with the player + .actor_collisions(player_ent) + .into_iter() + // Filter out anything not an item + .filter_map(|ent| items.get(ent).ok().map(|x| (ent, x))) + // Filter out any items that are being held by another player + .filter(|(_ent, (parent, _))| parent.is_none()) + .collect::>(); + + // Sort the items to provide deterministic item selection if we hare touching multiples + colliders.sort_by_key(|(_, (_, rollback))| rollback.id()); // If we are already carrying an item } else {