fix(inventory): decode block-placement and swing hands via from_packet_id (#2876)

The placement and swing packet 'hand' fields use 0 = main hand, but they were
decoded with TryFrom<i32>, which maps 0 -> Hand::Left (that conversion is for
the client's dominant-hand setting). Hand::Left means off-hand in the inventory
API, so the decremented stack was written back to the off-hand instead of the
main hand, causing non-consumed placement and duplication into the off-hand.

Use Hand::from_packet_id for these packet fields and read the item via
inventory.get_stack_in_hand, matching the existing use_item handler.
This commit is contained in:
QiuHu
2026-08-13 20:23:58 +08:00
committed by GitHub
parent a3ab25f53e
commit 24d9dbdc6b

View File

@@ -1354,7 +1354,7 @@ impl JavaClient {
swing_arm: SSwingArm,
) {
player.update_last_action_time();
let Ok(hand) = Hand::try_from(swing_arm.hand.0) else {
let Ok(hand) = Hand::from_packet_id(swing_arm.hand.0) else {
self.kick(TextComponent::text("Invalid hand")).await;
return;
};
@@ -2284,7 +2284,7 @@ impl JavaClient {
return Err(BlockPlacingError::InvalidBlockFace);
};
let Ok(hand) = Hand::try_from(use_item_on.hand.0) else {
let Ok(hand) = Hand::from_packet_id(use_item_on.hand.0) else {
return Err(BlockPlacingError::InvalidHand);
};
@@ -2299,11 +2299,8 @@ impl JavaClient {
let held_item_empty = held_item.is_empty();
let off_hand_item_empty = off_hand_item.is_empty();
let item_id = if matches!(hand, Hand::Left) {
held_item.item.id
} else {
off_hand_item.item.id
};
let mut item = inventory.get_stack_in_hand(hand).await;
let item_id = item.item.id;
player
.increment_stat(StatisticCategory::Used, item_id as i32, 1)
.await;
@@ -2333,12 +2330,7 @@ impl JavaClient {
}
}}
let mut item = if matches!(hand, Hand::Left) {
held_item
} else {
off_hand_item
};
let equipment_slot = if matches!(hand, Hand::Left) {
let equipment_slot = if matches!(hand, Hand::Right) {
EquipmentSlot::MAIN_HAND
} else {
EquipmentSlot::OFF_HAND
@@ -2371,7 +2363,7 @@ impl JavaClient {
}
}
let slot_index = if matches!(hand, Hand::Left) {
let slot_index = if matches!(hand, Hand::Right) {
inventory.get_selected_slot() as usize
} else {
PlayerInventory::OFF_HAND_SLOT