diff options
| author | mat <git@matdoes.dev> | 2025-09-28 13:10:04 -0545 |
|---|---|---|
| committer | mat <git@matdoes.dev> | 2025-09-28 13:10:04 -0545 |
| commit | 2c8b7c5c2c9297273abfba8f7743f1bc25f166b1 (patch) | |
| tree | 3d3aded400100c136287fa59293ce26c61644d00 /azalea-client/src/plugins/inventory.rs | |
| parent | e2ed19c1ed92f0dccc881d835d9ac6e0f7f834c0 (diff) | |
| download | azalea-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.rs | 213 |
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() { |
