aboutsummaryrefslogtreecommitdiff
path: root/azalea-client/src/plugins/inventory.rs
diff options
context:
space:
mode:
authormat <git@matdoes.dev>2025-09-28 13:10:04 -0545
committermat <git@matdoes.dev>2025-09-28 13:10:04 -0545
commit2c8b7c5c2c9297273abfba8f7743f1bc25f166b1 (patch)
tree3d3aded400100c136287fa59293ce26c61644d00 /azalea-client/src/plugins/inventory.rs
parente2ed19c1ed92f0dccc881d835d9ac6e0f7f834c0 (diff)
downloadazalea-drasl-2c8b7c5c2c9297273abfba8f7743f1bc25f166b1.tar.xz
upgrade bevy to 0.17.0-rc.2
Diffstat (limited to 'azalea-client/src/plugins/inventory.rs')
-rw-r--r--azalea-client/src/plugins/inventory.rs213
1 files changed, 94 insertions, 119 deletions
diff --git a/azalea-client/src/plugins/inventory.rs b/azalea-client/src/plugins/inventory.rs
index 968a805b..448f9e95 100644
--- a/azalea-client/src/plugins/inventory.rs
+++ b/azalea-client/src/plugins/inventory.rs
@@ -28,22 +28,10 @@ use crate::{Client, packet::game::SendPacketEvent, respawn::perform_respawn};
pub struct InventoryPlugin;
impl Plugin for InventoryPlugin {
fn build(&self, app: &mut App) {
- app.add_event::<ClientsideCloseContainerEvent>()
- .add_event::<MenuOpenedEvent>()
- .add_event::<CloseContainerEvent>()
- .add_event::<ContainerClickEvent>()
- .add_event::<SetContainerContentEvent>()
- .add_event::<SetSelectedHotbarSlotEvent>()
+ app.add_message::<SetSelectedHotbarSlotEvent>()
.add_systems(
Update,
- (
- handle_set_selected_hotbar_slot_event,
- handle_menu_opened_event,
- handle_container_click_event,
- handle_container_close_event,
- handle_client_side_close_container_event,
- )
- .chain()
+ handle_set_selected_hotbar_slot_event
.in_set(InventorySet)
.before(perform_respawn),
)
@@ -53,6 +41,7 @@ impl Plugin for InventoryPlugin {
)
.add_observer(handle_client_side_close_container_trigger)
.add_observer(handle_menu_opened_trigger)
+ .add_observer(handle_container_close_event)
.add_observer(handle_set_container_content_trigger);
}
}
@@ -64,9 +53,7 @@ impl Client {
/// Return the menu that is currently open. If no menu is open, this will
/// have the player's inventory.
pub fn menu(&self) -> Menu {
- let mut ecs = self.ecs.lock();
- let inventory = self.query::<&Inventory>(&mut ecs);
- inventory.menu().clone()
+ self.query_self::<&Inventory, _>(|inv| inv.menu().clone())
}
/// Returns the index of the hotbar slot that's currently selected.
@@ -77,15 +64,17 @@ impl Client {
///
/// You can use [`Self::set_selected_hotbar_slot`] to change it.
pub fn selected_hotbar_slot(&self) -> u8 {
- let mut ecs = self.ecs.lock();
- let inventory = self.query::<&Inventory>(&mut ecs);
- inventory.selected_hotbar_slot
+ self.query_self::<&Inventory, _>(|inv| inv.selected_hotbar_slot)
}
/// Update the selected hotbar slot index.
///
/// This will run next `Update`, so you might want to call
/// `bot.wait_updates(1)` after calling this if you're using `azalea`.
+ ///
+ /// # Panics
+ ///
+ /// This will panic if `new_hotbar_slot_index` is not in the range 0..=8.
pub fn set_selected_hotbar_slot(&self, new_hotbar_slot_index: u8) {
assert!(
new_hotbar_slot_index < 9,
@@ -93,7 +82,7 @@ impl Client {
);
let mut ecs = self.ecs.lock();
- ecs.send_event(SetSelectedHotbarSlotEvent {
+ ecs.write_message(SetSelectedHotbarSlotEvent {
entity: self.entity,
slot: new_hotbar_slot_index,
});
@@ -736,30 +725,25 @@ impl Default for Inventory {
/// To watch for the menu being closed, you could use
/// [`ClientsideCloseContainerEvent`]. To close it manually, use
/// [`CloseContainerEvent`].
-#[derive(Event, Debug, Clone)]
+#[derive(EntityEvent, Debug, Clone)]
pub struct MenuOpenedEvent {
pub entity: Entity,
pub window_id: i32,
pub menu_type: MenuKind,
pub title: FormattedText,
}
-fn handle_menu_opened_trigger(event: Trigger<MenuOpenedEvent>, mut query: Query<&mut Inventory>) {
+fn handle_menu_opened_trigger(event: On<MenuOpenedEvent>, mut query: Query<&mut Inventory>) {
let mut inventory = query.get_mut(event.entity).unwrap();
inventory.id = event.window_id;
inventory.container_menu = Some(Menu::from_kind(event.menu_type));
inventory.container_menu_title = Some(event.title.clone());
}
-pub fn handle_menu_opened_event(mut events: EventReader<MenuOpenedEvent>, mut commands: Commands) {
- for event in events.read() {
- commands.trigger(event.clone());
- }
-}
/// Tell the server that we want to close a container.
///
/// Note that this is also sent when the client closes its own inventory, even
/// though there is no packet for opening its inventory.
-#[derive(Event)]
+#[derive(EntityEvent)]
pub struct CloseContainerEvent {
pub entity: Entity,
/// The ID of the container to close. 0 for the player's inventory. If this
@@ -767,31 +751,28 @@ pub struct CloseContainerEvent {
pub id: i32,
}
fn handle_container_close_event(
- query: Query<(Entity, &Inventory)>,
- mut events: EventReader<CloseContainerEvent>,
- mut client_side_events: EventWriter<ClientsideCloseContainerEvent>,
+ close_container: On<CloseContainerEvent>,
mut commands: Commands,
+ query: Query<(Entity, &Inventory)>,
) {
- for event in events.read() {
- let (entity, inventory) = query.get(event.entity).unwrap();
- if event.id != inventory.id {
- warn!(
- "Tried to close container with ID {}, but the current container ID is {}",
- event.id, inventory.id
- );
- continue;
- }
-
- commands.trigger(SendPacketEvent::new(
- entity,
- ServerboundContainerClose {
- container_id: inventory.id,
- },
- ));
- client_side_events.write(ClientsideCloseContainerEvent {
- entity: event.entity,
- });
+ let (entity, inventory) = query.get(close_container.entity).unwrap();
+ if close_container.id != inventory.id {
+ warn!(
+ "Tried to close container with ID {}, but the current container ID is {}",
+ close_container.id, inventory.id
+ );
+ return;
}
+
+ commands.trigger(SendPacketEvent::new(
+ entity,
+ ServerboundContainerClose {
+ container_id: inventory.id,
+ },
+ ));
+ commands.trigger(ClientsideCloseContainerEvent {
+ entity: close_container.entity,
+ });
}
/// A Bevy trigger that's fired when our client closed a container.
@@ -802,12 +783,12 @@ fn handle_container_close_event(
///
/// If you want to watch for a container being opened, you should use
/// [`MenuOpenedEvent`].
-#[derive(Event, Clone)]
+#[derive(EntityEvent, Clone)]
pub struct ClientsideCloseContainerEvent {
pub entity: Entity,
}
pub fn handle_client_side_close_container_trigger(
- event: Trigger<ClientsideCloseContainerEvent>,
+ event: On<ClientsideCloseContainerEvent>,
mut query: Query<&mut Inventory>,
) {
let mut inventory = query.get_mut(event.entity).unwrap();
@@ -838,126 +819,120 @@ pub fn handle_client_side_close_container_trigger(
inventory.id = 0;
inventory.container_menu_title = None;
}
-pub fn handle_client_side_close_container_event(
- mut commands: Commands,
- mut events: EventReader<ClientsideCloseContainerEvent>,
-) {
- for event in events.read() {
- commands.trigger(event.clone());
- }
-}
-#[derive(Event, Debug)]
+#[derive(EntityEvent, Debug)]
pub struct ContainerClickEvent {
pub entity: Entity,
pub window_id: i32,
pub operation: ClickOperation,
}
pub fn handle_container_click_event(
+ mut commands: Commands,
+ container_click: On<ContainerClickEvent>,
mut query: Query<(
Entity,
&mut Inventory,
Option<&PlayerAbilities>,
&InstanceName,
)>,
- mut events: EventReader<ContainerClickEvent>,
- mut commands: Commands,
instance_container: Res<InstanceContainer>,
) {
- for event in events.read() {
- let (entity, mut inventory, player_abilities, instance_name) =
- query.get_mut(event.entity).unwrap();
- if inventory.id != event.window_id {
- error!(
- "Tried to click container with ID {}, but the current container ID is {}. Click packet won't be sent.",
- event.window_id, inventory.id
- );
- continue;
- }
-
- let Some(instance) = instance_container.get(instance_name) else {
- continue;
- };
-
- let old_slots = inventory.menu().slots();
- inventory.simulate_click(
- &event.operation,
- player_abilities.unwrap_or(&PlayerAbilities::default()),
+ let (entity, mut inventory, player_abilities, instance_name) =
+ query.get_mut(container_click.entity).unwrap();
+ if inventory.id != container_click.window_id {
+ error!(
+ "Tried to click container with ID {}, but the current container ID is {}. Click packet won't be sent.",
+ container_click.window_id, inventory.id
);
- let new_slots = inventory.menu().slots();
+ return;
+ }
- let registry_holder = &instance.read().registries;
-
- // see which slots changed after clicking and put them in the map the server
- // uses this to check if we desynced
- let mut changed_slots: IndexMap<u16, HashedStack> = IndexMap::new();
- for (slot_index, old_slot) in old_slots.iter().enumerate() {
- let new_slot = &new_slots[slot_index];
- if old_slot != new_slot {
- changed_slots.insert(
- slot_index as u16,
- HashedStack::from_item_stack(new_slot, registry_holder),
- );
- }
- }
+ let Some(instance) = instance_container.get(instance_name) else {
+ return;
+ };
- commands.trigger(SendPacketEvent::new(
- entity,
- ServerboundContainerClick {
- container_id: event.window_id,
- state_id: inventory.state_id,
- slot_num: event.operation.slot_num().map(|n| n as i16).unwrap_or(-999),
- button_num: event.operation.button_num(),
- click_type: event.operation.click_type(),
- changed_slots,
- carried_item: HashedStack::from_item_stack(&inventory.carried, registry_holder),
- },
- ));
+ let old_slots = inventory.menu().slots();
+ inventory.simulate_click(
+ &container_click.operation,
+ player_abilities.unwrap_or(&PlayerAbilities::default()),
+ );
+ let new_slots = inventory.menu().slots();
+
+ let registry_holder = &instance.read().registries;
+
+ // see which slots changed after clicking and put them in the map the server
+ // uses this to check if we desynced
+ let mut changed_slots: IndexMap<u16, HashedStack> = IndexMap::new();
+ for (slot_index, old_slot) in old_slots.iter().enumerate() {
+ let new_slot = &new_slots[slot_index];
+ if old_slot != new_slot {
+ changed_slots.insert(
+ slot_index as u16,
+ HashedStack::from_item_stack(new_slot, registry_holder),
+ );
+ }
}
+
+ commands.trigger(SendPacketEvent::new(
+ entity,
+ ServerboundContainerClick {
+ container_id: container_click.window_id,
+ state_id: inventory.state_id,
+ slot_num: container_click
+ .operation
+ .slot_num()
+ .map(|n| n as i16)
+ .unwrap_or(-999),
+ button_num: container_click.operation.button_num(),
+ click_type: container_click.operation.click_type(),
+ changed_slots,
+ carried_item: HashedStack::from_item_stack(&inventory.carried, registry_holder),
+ },
+ ));
}
/// Sent from the server when the contents of a container are replaced.
///
/// Usually triggered by the `ContainerSetContent` packet.
-#[derive(Event)]
+#[derive(EntityEvent)]
pub struct SetContainerContentEvent {
pub entity: Entity,
pub slots: Vec<ItemStack>,
pub container_id: i32,
}
pub fn handle_set_container_content_trigger(
- event: Trigger<SetContainerContentEvent>,
+ set_container_content: On<SetContainerContentEvent>,
mut query: Query<&mut Inventory>,
) {
- let mut inventory = query.get_mut(event.entity).unwrap();
+ let mut inventory = query.get_mut(set_container_content.entity).unwrap();
- if event.container_id != inventory.id {
+ if set_container_content.container_id != inventory.id {
warn!(
"Got SetContainerContentEvent for container with ID {}, but the current container ID is {}",
- event.container_id, inventory.id
+ set_container_content.container_id, inventory.id
);
return;
}
let menu = inventory.menu_mut();
- for (i, slot) in event.slots.iter().enumerate() {
+ for (i, slot) in set_container_content.slots.iter().enumerate() {
if let Some(slot_mut) = menu.slot_mut(i) {
*slot_mut = slot.clone();
}
}
}
-/// An ECS event to switch our hand to a different hotbar slot.
+/// An ECS message to switch our hand to a different hotbar slot.
///
/// This is equivalent to using the scroll wheel or number keys in Minecraft.
-#[derive(Event)]
+#[derive(Message)]
pub struct SetSelectedHotbarSlotEvent {
pub entity: Entity,
/// The hotbar slot to select. This should be in the range 0..=8.
pub slot: u8,
}
pub fn handle_set_selected_hotbar_slot_event(
- mut events: EventReader<SetSelectedHotbarSlotEvent>,
+ mut events: MessageReader<SetSelectedHotbarSlotEvent>,
mut query: Query<&mut Inventory>,
) {
for event in events.read() {