1
2
Fork 0
mirror of https://github.com/mat-1/azalea.git synced 2025-08-02 06:16:04 +00:00

replace Client::get_open_container and view_container_or_inventory with get_inventory

This commit is contained in:
mat 2025-06-09 13:14:20 -11:00
parent 40bcb62a77
commit 086f979a28
3 changed files with 66 additions and 113 deletions

View file

@ -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() {

View file

@ -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;

View file

@ -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<Output = Option<ContainerHandle>> + Send;
fn open_inventory(&self) -> Option<ContainerHandle>;
fn get_held_item(&self) -> ItemStack;
fn get_open_container(&self) -> Option<ContainerHandleRef>;
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<Output = Option<ContainerHandle>> + 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<ContainerHandle>;
/// 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<ContainerHandle> {
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<ContainerHandle> {
let ecs = self.ecs.lock();
let inventory = ecs.get::<Inventory>(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::<Inventory>(self.entity).expect("no inventory");
ContainerHandleRef::new(inventory.id, self.clone())
}
fn get_held_item(&self) -> ItemStack {
self.map_get_component::<Inventory, _>(|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<ContainerHandleRef> {
let ecs = self.ecs.lock();
let inventory = ecs.get::<Inventory>(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| {
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<usize>) {
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<usize>) {
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<usize>) {
self.click(PickupClick::Right {
slot: Some(slot.into() as u16),
});
}
pub fn click(&self, operation: impl Into<ClickOperation>) {
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<Menu> {
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<Vec<ItemStack>> {
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<Vec<ItemStack>> {
self.0.slots()
}
/// Closes the inventory by dropping the handle.
pub fn close(self) {
// implicitly calls drop
}
pub fn click(&self, operation: impl Into<ClickOperation>) {
self.0.click(operation);
}
/// A shortcut for [`Self::click`] with `PickupClick::Left`.
pub fn left_click(&self, slot: impl Into<usize>) {
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<usize>) {
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<usize>) {
self.click(PickupClick::Right {
slot: Some(slot.into() as u16),
});
}
}
#[derive(Component, Debug)]