Skip to content

Commit e76e913

Browse files
authored
refactor held item into a new component (#356)
## Description This moves the `held_item_slot` field in `ClientInventoryState` to a new component: `HeldItem` related: pr #355
1 parent 6338fc6 commit e76e913

File tree

3 files changed

+45
-33
lines changed

3 files changed

+45
-33
lines changed

crates/valence/examples/building.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![allow(clippy::type_complexity)]
22

3-
use valence::inventory::ClientInventoryState;
3+
use valence::inventory::HeldItem;
44
use valence::prelude::*;
55
use valence_client::interact_block::InteractBlockEvent;
66

@@ -109,22 +109,22 @@ fn digging_survival_mode(
109109
}
110110

111111
fn place_blocks(
112-
mut clients: Query<(&mut Inventory, &GameMode, &ClientInventoryState)>,
112+
mut clients: Query<(&mut Inventory, &GameMode, &HeldItem)>,
113113
mut instances: Query<&mut Instance>,
114114
mut events: EventReader<InteractBlockEvent>,
115115
) {
116116
let mut instance = instances.single_mut();
117117

118118
for event in events.iter() {
119-
let Ok((mut inventory, game_mode, inv_state)) = clients.get_mut(event.client) else {
119+
let Ok((mut inventory, game_mode, held)) = clients.get_mut(event.client) else {
120120
continue;
121121
};
122122
if event.hand != Hand::Main {
123123
continue;
124124
}
125125

126126
// get the held item
127-
let slot_id = inv_state.held_item_slot();
127+
let slot_id = held.slot();
128128
let Some(stack) = inventory.slot(slot_id) else {
129129
// no item in the slot
130130
continue;

crates/valence/src/tests/inventory.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ use valence_inventory::packet::{
66
OpenScreenS2c, ScreenHandlerSlotUpdateS2c, SlotChange, UpdateSelectedSlotC2s,
77
};
88
use valence_inventory::{
9-
convert_to_player_slot_id, ClientInventoryState, CursorItem, DropItemStack, Inventory,
10-
InventoryKind, OpenInventory,
9+
convert_to_player_slot_id, ClientInventoryState, CursorItem, DropItemStack, HeldItem,
10+
Inventory, InventoryKind, OpenInventory,
1111
};
1212

1313
use super::*;
@@ -474,12 +474,12 @@ fn test_should_handle_set_held_item() {
474474
app.update();
475475

476476
// Make assertions
477-
let inv_state = app
477+
let held = app
478478
.world
479-
.get::<ClientInventoryState>(client_ent)
479+
.get::<HeldItem>(client_ent)
480480
.expect("could not find client");
481481

482-
assert_eq!(inv_state.held_item_slot(), 40);
482+
assert_eq!(held.slot(), 40);
483483
}
484484

485485
#[test]
@@ -602,11 +602,11 @@ mod dropping_items {
602602
app.update();
603603

604604
// Make assertions
605-
let inv_state = app
605+
let held = app
606606
.world
607-
.get::<ClientInventoryState>(client_ent)
607+
.get::<HeldItem>(client_ent)
608608
.expect("could not find client");
609-
assert_eq!(inv_state.held_item_slot(), 36);
609+
assert_eq!(held.slot(), 36);
610610
let inventory = app
611611
.world
612612
.get::<Inventory>(client_ent)

crates/valence_inventory/src/lib.rs

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -337,15 +337,9 @@ pub struct ClientInventoryState {
337337
/// on the `CursorItem` component to make maintaining accurate change
338338
/// detection for end users easier.
339339
client_updated_cursor_item: bool,
340-
// TODO: make this a separate modifiable component.
341-
held_item_slot: u16,
342340
}
343341

344342
impl ClientInventoryState {
345-
pub fn held_item_slot(&self) -> u16 {
346-
self.held_item_slot
347-
}
348-
349343
#[doc(hidden)]
350344
pub fn window_id(&self) -> u8 {
351345
self.window_id
@@ -357,6 +351,20 @@ impl ClientInventoryState {
357351
}
358352
}
359353

354+
/// Indicates which hotbar slot the player is currently holding.
355+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Component)]
356+
pub struct HeldItem {
357+
held_item_slot: u16,
358+
}
359+
360+
impl HeldItem {
361+
/// The slot ID of the currently held item, in the range 36-44 inclusive.
362+
/// This value is safe to use on the player's inventory directly.
363+
pub fn slot(&self) -> u16 {
364+
self.held_item_slot
365+
}
366+
}
367+
360368
/// The item stack that the client thinks it's holding under the mouse
361369
/// cursor.
362370
#[derive(Component, Clone, PartialEq, Default, Debug)]
@@ -533,6 +541,8 @@ fn init_new_client_inventories(clients: Query<Entity, Added<Client>>, mut comman
533541
state_id: Wrapping(0),
534542
slots_changed: 0,
535543
client_updated_cursor_item: false,
544+
},
545+
HeldItem {
536546
// First slot of the hotbar.
537547
held_item_slot: 36,
538548
},
@@ -1039,43 +1049,42 @@ fn handle_click_slot(
10391049

10401050
fn handle_player_actions(
10411051
mut packets: EventReader<PacketEvent>,
1042-
mut clients: Query<(&mut Inventory, &mut ClientInventoryState)>,
1052+
mut clients: Query<(&mut Inventory, &mut ClientInventoryState, &HeldItem)>,
10431053
mut drop_item_stack_events: EventWriter<DropItemStack>,
10441054
) {
10451055
for packet in packets.iter() {
10461056
if let Some(pkt) = packet.decode::<PlayerActionC2s>() {
10471057
match pkt.action {
10481058
PlayerAction::DropAllItems => {
1049-
if let Ok((mut inv, mut inv_state)) = clients.get_mut(packet.client) {
1050-
if let Some(stack) = inv.replace_slot(inv_state.held_item_slot, None) {
1051-
inv_state.slots_changed |= 1 << inv_state.held_item_slot;
1059+
if let Ok((mut inv, mut inv_state, &held)) = clients.get_mut(packet.client) {
1060+
if let Some(stack) = inv.replace_slot(held.slot(), None) {
1061+
inv_state.slots_changed |= 1 << held.slot();
10521062

10531063
drop_item_stack_events.send(DropItemStack {
10541064
client: packet.client,
1055-
from_slot: Some(inv_state.held_item_slot),
1065+
from_slot: Some(held.slot()),
10561066
stack,
10571067
});
10581068
}
10591069
}
10601070
}
10611071
PlayerAction::DropItem => {
1062-
if let Ok((mut inv, mut inv_state)) = clients.get_mut(packet.client) {
1063-
if let Some(mut stack) = inv.replace_slot(inv_state.held_item_slot(), None)
1064-
{
1072+
if let Ok((mut inv, mut inv_state, held)) = clients.get_mut(packet.client) {
1073+
if let Some(mut stack) = inv.replace_slot(held.slot(), None) {
10651074
if stack.count() > 1 {
10661075
inv.set_slot(
1067-
inv_state.held_item_slot(),
1076+
held.slot(),
10681077
stack.clone().with_count(stack.count() - 1),
10691078
);
10701079

10711080
stack.set_count(1);
10721081
}
10731082

1074-
inv_state.slots_changed |= 1 << inv_state.held_item_slot();
1083+
inv_state.slots_changed |= 1 << held.slot();
10751084

10761085
drop_item_stack_events.send(DropItemStack {
10771086
client: packet.client,
1078-
from_slot: Some(inv_state.held_item_slot()),
1087+
from_slot: Some(held.slot()),
10791088
stack,
10801089
})
10811090
}
@@ -1169,14 +1178,17 @@ pub struct UpdateSelectedSlot {
11691178

11701179
fn handle_update_selected_slot(
11711180
mut packets: EventReader<PacketEvent>,
1172-
mut clients: Query<&mut ClientInventoryState>,
1181+
mut clients: Query<&mut HeldItem>,
11731182
mut events: EventWriter<UpdateSelectedSlot>,
11741183
) {
11751184
for packet in packets.iter() {
11761185
if let Some(pkt) = packet.decode::<UpdateSelectedSlotC2s>() {
1177-
if let Ok(mut inv_state) = clients.get_mut(packet.client) {
1178-
// TODO: validate this.
1179-
inv_state.held_item_slot = convert_hotbar_slot_id(pkt.slot as u16);
1186+
if let Ok(mut held) = clients.get_mut(packet.client) {
1187+
if pkt.slot < 0 || pkt.slot > 8 {
1188+
// The client is trying to interact with a slot that does not exist, ignore.
1189+
continue;
1190+
}
1191+
held.held_item_slot = convert_hotbar_slot_id(pkt.slot as u16);
11801192

11811193
events.send(UpdateSelectedSlot {
11821194
client: packet.client,

0 commit comments

Comments
 (0)