refactor handle_click_slot to primarily emit ClickSlot events, and handle those in a new system

This commit is contained in:
Carson McManus 2023-06-05 15:14:03 -04:00
parent 6338fc6300
commit 475639dec0

View file

@ -25,6 +25,7 @@ use std::ops::Range;
use bevy_app::prelude::*; use bevy_app::prelude::*;
use bevy_ecs::prelude::*; use bevy_ecs::prelude::*;
use menu::OpenMenu;
use packet::{ use packet::{
ClickMode, ClickSlotC2s, CloseHandledScreenC2s, CloseScreenS2c, CreativeInventoryActionC2s, ClickMode, ClickSlotC2s, CloseHandledScreenC2s, CloseScreenS2c, CreativeInventoryActionC2s,
InventoryS2c, OpenScreenS2c, ScreenHandlerSlotUpdateS2c, SlotChange, UpdateSelectedSlotC2s, InventoryS2c, OpenScreenS2c, ScreenHandlerSlotUpdateS2c, SlotChange, UpdateSelectedSlotC2s,
@ -40,6 +41,7 @@ use valence_core::protocol::encode::WritePacket;
use valence_core::protocol::var_int::VarInt; use valence_core::protocol::var_int::VarInt;
use valence_core::text::Text; use valence_core::text::Text;
pub mod menu;
pub mod packet; pub mod packet;
mod validate; mod validate;
@ -65,7 +67,8 @@ impl Plugin for InventoryPlugin {
.add_systems( .add_systems(
( (
handle_update_selected_slot, handle_update_selected_slot,
handle_click_slot, emit_events_from_packets,
handle_click_slot.after(emit_events_from_packets),
handle_creative_inventory_action, handle_creative_inventory_action,
handle_close_handled_screen, handle_close_handled_screen,
handle_player_actions, handle_player_actions,
@ -332,11 +335,11 @@ pub struct ClientInventoryState {
state_id: Wrapping<i32>, state_id: Wrapping<i32>,
/// Tracks what slots have been changed by this client in this tick, so we /// Tracks what slots have been changed by this client in this tick, so we
/// don't need to send updates for them. /// don't need to send updates for them.
slots_changed: u64, pub(crate) slots_changed: u64,
/// Whether the client has updated the cursor item in this tick. This is not /// Whether the client has updated the cursor item in this tick. This is not
/// on the `CursorItem` component to make maintaining accurate change /// on the `CursorItem` component to make maintaining accurate change
/// detection for end users easier. /// detection for end users easier.
client_updated_cursor_item: bool, pub(crate) client_updated_cursor_item: bool,
// TODO: make this a separate modifiable component. // TODO: make this a separate modifiable component.
held_item_slot: u16, held_item_slot: u16,
} }
@ -754,7 +757,7 @@ pub struct DropItemStack {
pub stack: ItemStack, pub stack: ItemStack,
} }
fn handle_click_slot( fn emit_events_from_packets(
mut packets: EventReader<PacketEvent>, mut packets: EventReader<PacketEvent>,
mut clients: Query<( mut clients: Query<(
&mut Client, &mut Client,
@ -969,22 +972,6 @@ fn handle_click_slot(
continue; continue;
} }
cursor_item.set_if_neq(CursorItem(pkt.carried_item.clone()));
for slot in pkt.slot_changes.clone() {
if (0i16..target_inventory.slot_count() as i16).contains(&slot.idx) {
// The client is interacting with a slot in the target inventory.
target_inventory.set_slot(slot.idx as u16, slot.item);
open_inventory.client_changed |= 1 << slot.idx;
} else {
// The client is interacting with a slot in their own inventory.
let slot_id =
convert_to_player_slot_id(target_inventory.kind, slot.idx as u16);
client_inv.set_slot(slot_id, slot.item);
inv_state.slots_changed |= 1 << slot_id;
}
}
} else { } else {
// The client is interacting with their own inventory. // The client is interacting with their own inventory.
@ -1004,23 +991,6 @@ fn handle_click_slot(
continue; continue;
} }
cursor_item.set_if_neq(CursorItem(pkt.carried_item.clone()));
inv_state.client_updated_cursor_item = true;
for slot in pkt.slot_changes.clone() {
if (0i16..client_inv.slot_count() as i16).contains(&slot.idx) {
client_inv.set_slot(slot.idx as u16, slot.item);
inv_state.slots_changed |= 1 << slot.idx;
} else {
// The client is trying to interact with a slot that does not exist,
// ignore.
warn!(
"Client attempted to interact with slot {} which does not exist",
slot.idx
);
}
}
} }
click_slot_events.send(ClickSlot { click_slot_events.send(ClickSlot {
@ -1037,6 +1007,75 @@ fn handle_click_slot(
} }
} }
fn handle_click_slot(
mut click_slots: EventReader<ClickSlot>,
mut clients: Query<(
&mut Client,
&mut Inventory,
&mut ClientInventoryState,
Option<&mut OpenInventory>,
&mut CursorItem,
)>,
mut inventories: Query<&mut Inventory, Without<Client>>,
) {
for click in click_slots.iter() {
// The player is clicking a slot in an inventory.
let Ok((
mut client,
mut client_inv,
mut inv_state,
open_inventory,
mut cursor_item
)) = clients.get_mut(click.client) else {
// The client does not exist, ignore.
continue;
};
if let Some(mut open_inventory) = open_inventory {
// The player is interacting with an inventory that is open.
let Ok(mut target_inventory) = inventories.get_mut(open_inventory.entity) else {
// The inventory does not exist, ignore.
continue;
};
cursor_item.set_if_neq(CursorItem(click.carried_item.clone()));
inv_state.client_updated_cursor_item = true;
for slot in click.slot_changes.clone() {
if (0i16..target_inventory.slot_count() as i16).contains(&slot.idx) {
// The client is interacting with a slot in the target inventory.
target_inventory.set_slot(slot.idx as u16, slot.item);
open_inventory.client_changed |= 1 << slot.idx;
} else {
// The client is interacting with a slot in their own inventory.
let slot_id = convert_to_player_slot_id(target_inventory.kind, slot.idx as u16);
client_inv.set_slot(slot_id, slot.item);
inv_state.slots_changed |= 1 << slot_id;
}
}
} else {
// The client is interacting with their own inventory.
cursor_item.set_if_neq(CursorItem(click.carried_item.clone()));
inv_state.client_updated_cursor_item = true;
for slot in click.slot_changes.clone() {
if (0i16..client_inv.slot_count() as i16).contains(&slot.idx) {
client_inv.set_slot(slot.idx as u16, slot.item);
inv_state.slots_changed |= 1 << slot.idx;
} else {
// The client is trying to interact with a slot that does not exist,
// ignore.
warn!(
"Client attempted to interact with slot {} which does not exist",
slot.idx
);
}
}
}
}
}
fn handle_player_actions( fn handle_player_actions(
mut packets: EventReader<PacketEvent>, mut packets: EventReader<PacketEvent>,
mut clients: Query<(&mut Inventory, &mut ClientInventoryState)>, mut clients: Query<(&mut Inventory, &mut ClientInventoryState)>,