From 086f979a2895e7f15ec61e5704869a0cfc94d16f Mon Sep 17 00:00:00 2001 From: mat Date: Mon, 9 Jun 2025 13:14:20 -1100 Subject: [PATCH] replace Client::get_open_container and view_container_or_inventory with get_inventory --- .../tests/move_and_despawn_entity.rs | 2 - azalea-inventory/src/lib.rs | 3 +- azalea/src/container.rs | 174 +++++++----------- 3 files changed, 66 insertions(+), 113 deletions(-) diff --git a/azalea-client/tests/move_and_despawn_entity.rs b/azalea-client/tests/move_and_despawn_entity.rs index 09d901bc..d8298ff2 100644 --- a/azalea-client/tests/move_and_despawn_entity.rs +++ b/azalea-client/tests/move_and_despawn_entity.rs @@ -3,7 +3,6 @@ use azalea_core::{ position::{ChunkPos, Vec3}, resource_location::ResourceLocation, }; -use azalea_entity::metadata::Cow; use azalea_protocol::{ common::movements::{PositionMoveRotation, RelativeMovements}, packets::{ @@ -13,7 +12,6 @@ use azalea_protocol::{ }; use azalea_registry::{DataRegistry, DimensionType, EntityKind}; use azalea_world::MinecraftEntityId; -use bevy_ecs::query::With; #[test] fn test_move_and_despawn_entity() { diff --git a/azalea-inventory/src/lib.rs b/azalea-inventory/src/lib.rs index 0f74ba3a..3bcb0019 100644 --- a/azalea-inventory/src/lib.rs +++ b/azalea-inventory/src/lib.rs @@ -1,4 +1,5 @@ -/// Representations of various inventory data structures in Minecraft. +//! Representations of various inventory data structures in Minecraft. + pub mod components; pub mod item; pub mod operations; diff --git a/azalea/src/container.rs b/azalea/src/container.rs index 6c4e86cc..f452b1be 100644 --- a/azalea/src/container.rs +++ b/azalea/src/container.rs @@ -14,6 +14,7 @@ use azalea_physics::collision::BlockWithShape; use azalea_protocol::packets::game::ClientboundGamePacket; use bevy_app::{App, Plugin, Update}; use bevy_ecs::{component::Component, prelude::EventReader, system::Commands}; +use derive_more::Deref; use futures_lite::Future; use crate::bot::BotClientExt; @@ -26,17 +27,6 @@ impl Plugin for ContainerPlugin { } pub trait ContainerClientExt { - fn open_container_at( - &self, - pos: BlockPos, - ) -> impl Future> + Send; - fn open_inventory(&self) -> Option; - fn get_held_item(&self) -> ItemStack; - fn get_open_container(&self) -> Option; - fn view_container_or_inventory(&self) -> Menu; -} - -impl ContainerClientExt for Client { /// Open a container in the world, like a chest. Use /// [`Client::open_inventory`] to open your own inventory. /// @@ -54,6 +44,39 @@ impl ContainerClientExt for Client { /// let container = bot.open_container_at(target_pos).await; /// # } /// ``` + fn open_container_at( + &self, + pos: BlockPos, + ) -> impl Future> + Send; + /// Open the player's inventory. This will return None if another + /// container is open. + /// + /// Note that this will send a packet to the server once it's dropped. Also, + /// due to how it's implemented, you could call this function multiple times + /// while another inventory handle already exists (but you shouldn't). + /// + /// If you just want to get the items in the player's inventory without + /// sending any packets, use [`Client::menu`], [`Menu::player_slots_range`], + /// and [`Menu::slots`]. + fn open_inventory(&self) -> Option; + /// Returns a [`ContainerHandleRef`] to the client's currently open + /// container, or their inventory. + /// + /// This will not send a packet to close the container when it's dropped, + /// which may cause anticheat compatibility issues if you modify your + /// inventory without closing it afterwards. + /// + /// To simulate opening your own inventory (like pressing 'e') in a way that + /// won't trigger anticheats, use [`Client::open_inventory`]. + /// + /// To open a container in the world, use [`Client::open_container_at`]. + fn get_inventory(&self) -> ContainerHandleRef; + /// Get the item in the bot's hotbar that is currently being held in its + /// main hand. + fn get_held_item(&self) -> ItemStack; +} + +impl ContainerClientExt for Client { async fn open_container_at(&self, pos: BlockPos) -> Option { let mut ticks = self.get_tick_broadcaster(); // wait until it's not air (up to 10 ticks) @@ -92,20 +115,9 @@ impl ContainerClientExt for Client { } } - /// Open the player's inventory. This will return None if another - /// container is open. - /// - /// Note that this will send a packet to the server once it's dropped. Also, - /// due to how it's implemented, you could call this function multiple times - /// while another inventory handle already exists (but you shouldn't). - /// - /// If you just want to get the items in the player's inventory without - /// sending any packets, use [`Client::menu`], [`Menu::player_slots_range`], - /// and [`Menu::slots`]. fn open_inventory(&self) -> Option { let ecs = self.ecs.lock(); let inventory = ecs.get::(self.entity).expect("no inventory"); - if inventory.id == 0 { Some(ContainerHandle::new(0, self.clone())) } else { @@ -113,46 +125,16 @@ impl ContainerClientExt for Client { } } - /// Get the item in the bot's hotbar that is currently being held in its - /// main hand. + fn get_inventory(&self) -> ContainerHandleRef { + let ecs = self.ecs.lock(); + let inventory = ecs.get::(self.entity).expect("no inventory"); + ContainerHandleRef::new(inventory.id, self.clone()) + } + fn get_held_item(&self) -> ItemStack { self.map_get_component::(|inventory| inventory.held_item()) .expect("no inventory") } - - /// Get a handle to the open container. This will return None if no - /// container is open. This will not close the container when it's dropped. - /// - /// See [`Client::open_inventory`] or [`Client::menu`] if you want to open - /// your own inventory. - fn get_open_container(&self) -> Option { - let ecs = self.ecs.lock(); - let inventory = ecs.get::(self.entity).expect("no inventory"); - - if inventory.id == 0 { - None - } else { - Some(ContainerHandleRef { - id: inventory.id, - client: self.clone(), - }) - } - } - - /// Returns the player's currently open container menu, or their inventory - /// if no container is open. - /// - /// This tries to access the client's [`Inventory::container_menu`] and - /// falls back to [`Inventory::inventory_menu`]. - fn view_container_or_inventory(&self) -> Menu { - self.map_get_component::(|inventory| { - inventory - .container_menu - .clone() - .unwrap_or(inventory.inventory_menu.clone()) - }) - .expect("no inventory") - } } /// A handle to a container that may be open. This does not close the container @@ -169,6 +151,10 @@ impl Debug for ContainerHandleRef { } } impl ContainerHandleRef { + pub fn new(id: i32, client: Client) -> Self { + Self { id, client } + } + pub fn close(&self) { self.client.ecs.lock().send_event(CloseContainerEvent { entity: self.client.entity, @@ -219,6 +205,25 @@ impl ContainerHandleRef { self.menu().map(|menu| menu.slots()) } + /// A shortcut for [`Self::click`] with `PickupClick::Left`. + pub fn left_click(&self, slot: impl Into) { + self.click(PickupClick::Left { + slot: Some(slot.into() as u16), + }); + } + /// A shortcut for [`Self::click`] with `QuickMoveClick::Left`. + pub fn shift_click(&self, slot: impl Into) { + self.click(QuickMoveClick::Left { + slot: slot.into() as u16, + }); + } + /// A shortcut for [`Self::click`] with `PickupClick::Right`. + pub fn right_click(&self, slot: impl Into) { + self.click(PickupClick::Right { + slot: Some(slot.into() as u16), + }); + } + pub fn click(&self, operation: impl Into) { let operation = operation.into(); self.client.ecs.lock().send_event(ContainerClickEvent { @@ -231,6 +236,7 @@ impl ContainerHandleRef { /// A handle to the open container. The container will be closed once this is /// dropped. +#[derive(Deref)] pub struct ContainerHandle(ContainerHandleRef); impl Drop for ContainerHandle { @@ -250,62 +256,10 @@ impl ContainerHandle { Self(ContainerHandleRef { id, client }) } - /// Get the id of the container. If this is 0, that means it's the player's - /// inventory. Otherwise, the number isn't really meaningful since only one - /// container can be open at a time. - pub fn id(&self) -> i32 { - self.0.id() - } - - /// Returns the menu of the container. If the container is closed, this - /// will return `None`. - /// - /// Note that any modifications you make to the `Menu` you're given will not - /// actually cause any packets to be sent. If you're trying to modify your - /// inventory, use [`ContainerHandle::click`] instead - pub fn menu(&self) -> Option { - self.0.menu() - } - - /// Returns the item slots in the container, not including the player's - /// inventory. If the container is closed, this will return `None`. - pub fn contents(&self) -> Option> { - self.0.contents() - } - - /// Return the contents of the menu, including the player's inventory. If - /// the container is closed, this will return `None`. - pub fn slots(&self) -> Option> { - self.0.slots() - } - /// Closes the inventory by dropping the handle. pub fn close(self) { // implicitly calls drop } - - pub fn click(&self, operation: impl Into) { - self.0.click(operation); - } - - /// A shortcut for [`Self::click`] with `PickupClick::Left`. - pub fn left_click(&self, slot: impl Into) { - self.click(PickupClick::Left { - slot: Some(slot.into() as u16), - }); - } - /// A shortcut for [`Self::click`] with `QuickMoveClick::Left`. - pub fn shift_click(&self, slot: impl Into) { - self.click(QuickMoveClick::Left { - slot: slot.into() as u16, - }); - } - /// A shortcut for [`Self::click`] with `PickupClick::Right`. - pub fn right_click(&self, slot: impl Into) { - self.click(PickupClick::Right { - slot: Some(slot.into() as u16), - }); - } } #[derive(Component, Debug)]