diff --git a/crates/valence/src/inventory.rs b/crates/valence/src/inventory.rs index 8fc7ee0..255ba95 100644 --- a/crates/valence/src/inventory.rs +++ b/crates/valence/src/inventory.rs @@ -530,7 +530,9 @@ fn update_player_inventories( } if cursor_item.is_changed() && !inv_state.client_updated_cursor_item { - inv_state.state_id += 1; + // Contrary to what you might think, we actually don't want to increment the + // state ID here because the client doesn't actually acknowledge the + // state_id change for this packet specifically. See #304. client.write_packet(&ScreenHandlerSlotUpdateS2c { window_id: -1, @@ -1501,6 +1503,39 @@ mod test { Ok(()) } + #[test] + fn should_not_increment_state_id_on_cursor_item_change() -> anyhow::Result<()> { + let mut app = App::new(); + let (client_ent, mut client_helper) = scenario_single_client(&mut app); + + let inv_state = app + .world + .get::(client_ent) + .expect("could not find client"); + let expected_state_id = inv_state.state_id.0; + + // Process a tick to get past the "on join" logic. + app.update(); + client_helper.clear_sent(); + + let mut cursor_item = app.world.get_mut::(client_ent).unwrap(); + cursor_item.0 = Some(ItemStack::new(ItemKind::Diamond, 2, None)); + + app.update(); + + // Make assertions + let inv_state = app + .world + .get::(client_ent) + .expect("could not find client"); + assert_eq!( + inv_state.state_id.0, expected_state_id, + "state id should not have changed" + ); + + Ok(()) + } + mod dropping_items { use valence_protocol::block_pos::BlockPos; use valence_protocol::packet::c2s::play::click_slot::{ClickMode, Slot};