From 1347f3549282397be6a46b8b7cb76a7900d0690a Mon Sep 17 00:00:00 2001 From: mat Date: Thu, 4 Jan 2024 01:55:00 -0600 Subject: [PATCH] rename open_container to open_container_at and add get_open_container --- azalea-client/src/inventory.rs | 6 + azalea-core/src/game_type.rs | 6 +- azalea/examples/steal.rs | 2 +- azalea/examples/testbot.rs | 2 +- .../examples/todo/craft_dig_straight_down.rs | 2 +- azalea/src/container.rs | 116 ++++++++++++++---- 6 files changed, 101 insertions(+), 33 deletions(-) diff --git a/azalea-client/src/inventory.rs b/azalea-client/src/inventory.rs index 527feae78..bf421bf4d 100644 --- a/azalea-client/src/inventory.rs +++ b/azalea-client/src/inventory.rs @@ -90,6 +90,9 @@ pub struct InventoryComponent { /// The current container menu that the player has open. If no container is /// open, this will be `None`. pub container_menu: Option, + /// The custom name of the menu that's currently open. This is Some when + /// `container_menu` is Some. + pub container_menu_title: Option, /// The item that is currently held by the cursor. `Slot::Empty` if nothing /// is currently being held. /// @@ -566,6 +569,7 @@ impl Default for InventoryComponent { inventory_menu: Menu::Player(azalea_inventory::Player::default()), id: 0, container_menu: None, + container_menu_title: None, carried: ItemSlot::Empty, state_id: 0, quick_craft_status: QuickCraftStatusKind::Start, @@ -593,6 +597,7 @@ fn handle_menu_opened_event( let mut inventory = query.get_mut(event.entity).unwrap(); inventory.id = event.window_id as u8; inventory.container_menu = Some(Menu::from_kind(event.menu_type)); + inventory.container_menu_title = Some(event.title.clone()); } } @@ -651,6 +656,7 @@ pub fn handle_client_side_close_container_event( let mut inventory = query.get_mut(event.entity).unwrap(); inventory.container_menu = None; inventory.id = 0; + inventory.container_menu_title = None; } } diff --git a/azalea-core/src/game_type.rs b/azalea-core/src/game_type.rs index 99f0c0fea..7c7a43a82 100644 --- a/azalea-core/src/game_type.rs +++ b/azalea-core/src/game_type.rs @@ -1,6 +1,6 @@ use azalea_buf::{BufReadError, McBufReadable, McBufVarReadable, McBufWritable}; use std::io::{Cursor, Write}; -use tracing::warn; +use tracing::debug; /// A Minecraft gamemode, like survival or creative. #[derive(Hash, Copy, Clone, Debug, Default, Eq, PartialEq)] @@ -96,11 +96,11 @@ impl McBufReadable for GameMode { fn read_from(buf: &mut Cursor<&[u8]>) -> Result { let id = u32::var_read_from(buf)?; let id = id.try_into().unwrap_or_else(|_| { - warn!("Unknown game mode id {id}, defaulting to survival"); + debug!("Unknown game mode id {id}, defaulting to survival"); 0 }); Ok(GameMode::from_id(id).unwrap_or_else(|| { - warn!("Unknown game mode id {id}, defaulting to survival"); + debug!("Unknown game mode id {id}, defaulting to survival"); GameMode::Survival })) } diff --git a/azalea/examples/steal.rs b/azalea/examples/steal.rs index 408d7b9b4..c6ab46397 100644 --- a/azalea/examples/steal.rs +++ b/azalea/examples/steal.rs @@ -45,7 +45,7 @@ async fn handle(mut bot: Client, event: Event, state: State) -> anyhow::Result<( return Ok(()); }; // bot.goto(BlockPosGoal(chest_block)); - let Some(chest) = bot.open_container(chest_block).await else { + let Some(chest) = bot.open_container_at(chest_block).await else { println!("Couldn't open chest"); return Ok(()); }; diff --git a/azalea/examples/testbot.rs b/azalea/examples/testbot.rs index 7e7b2ca08..c9e64ef95 100644 --- a/azalea/examples/testbot.rs +++ b/azalea/examples/testbot.rs @@ -216,7 +216,7 @@ async fn handle(mut bot: Client, event: Event, _state: State) -> anyhow::Result< return Ok(()); }; bot.look_at(target_pos.center()); - let container = bot.open_container(target_pos).await; + let container = bot.open_container_at(target_pos).await; println!("container: {container:?}"); if let Some(container) = container { if let Some(contents) = container.contents() { diff --git a/azalea/examples/todo/craft_dig_straight_down.rs b/azalea/examples/todo/craft_dig_straight_down.rs index 6672eaa49..7b75d2db9 100644 --- a/azalea/examples/todo/craft_dig_straight_down.rs +++ b/azalea/examples/todo/craft_dig_straight_down.rs @@ -38,7 +38,7 @@ async fn handle(bot: Client, event: Event, state: State) -> anyhow::Result<()> { bot.goto(pathfinder::Goals::NearXZ(5, azalea::BlockXZ(0, 0))) .await; let chest = bot - .open_container(&bot.world().find_block(azalea::Block::Chest)) + .open_container_at(&bot.world().find_block(azalea::Block::Chest)) .await .unwrap(); bot.take_amount_from_container(&chest, 5, |i| i.id == "#minecraft:planks") diff --git a/azalea/src/container.rs b/azalea/src/container.rs index 0f4170613..c354390ea 100644 --- a/azalea/src/container.rs +++ b/azalea/src/container.rs @@ -23,11 +23,12 @@ impl Plugin for ContainerPlugin { } pub trait ContainerClientExt { - fn open_container( + fn open_container_at( &mut self, pos: BlockPos, ) -> impl Future> + Send; fn open_inventory(&mut self) -> Option; + fn get_open_container(&self) -> Option; } impl ContainerClientExt for Client { @@ -45,10 +46,10 @@ impl ContainerClientExt for Client { /// bot.chat("no chest found"); /// return; /// }; - /// let container = bot.open_container(target_pos).await; + /// let container = bot.open_container_at(target_pos).await; /// # } /// ``` - async fn open_container(&mut self, pos: BlockPos) -> Option { + async fn open_container_at(&mut self, pos: BlockPos) -> Option { self.ecs .lock() .entity_mut(self.entity) @@ -70,10 +71,7 @@ impl ContainerClientExt for Client { if inventory.id == 0 { None } else { - Some(ContainerHandle { - id: inventory.id, - client: self.clone(), - }) + Some(ContainerHandle::new(inventory.id, self.clone())) } } @@ -94,40 +92,55 @@ impl ContainerClientExt for Client { .expect("no inventory"); if inventory.id == 0 { - Some(ContainerHandle { - id: 0, - client: self.clone(), - }) + Some(ContainerHandle::new(0, self.clone())) } else { None } } + + /// 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(), + }) + } + } } -/// A handle to the open container. The container will be closed once this is -/// dropped. -pub struct ContainerHandle { - /// The id of the container. If this is 0, that means it's the player's - /// inventory. +/// A handle to a container that may be open. This does not close the container +/// when it's dropped. See [`ContainerHandle`] if that behavior is desired. +pub struct ContainerHandleRef { id: u8, client: Client, } -impl Drop for ContainerHandle { - fn drop(&mut self) { - self.client.ecs.lock().send_event(CloseContainerEvent { - entity: self.client.entity, - id: self.id, - }); - } -} -impl Debug for ContainerHandle { +impl Debug for ContainerHandleRef { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { f.debug_struct("ContainerHandle") - .field("id", &self.id) + .field("id", &self.id()) .finish() } } -impl ContainerHandle { +impl ContainerHandleRef { + pub fn close(&self) { + self.client.ecs.lock().send_event(CloseContainerEvent { + entity: self.client.entity, + id: self.id, + }); + } + /// 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. @@ -175,6 +188,55 @@ impl ContainerHandle { } } +/// A handle to the open container. The container will be closed once this is +/// dropped. +pub struct ContainerHandle(ContainerHandleRef); + +impl Drop for ContainerHandle { + fn drop(&mut self) { + self.0.close(); + } +} +impl Debug for ContainerHandle { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ContainerHandle") + .field("id", &self.id()) + .finish() + } +} +impl ContainerHandle { + fn new(id: u8, client: Client) -> Self { + 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) -> u8 { + 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() + } + + pub fn click(&self, operation: impl Into) { + self.0.click(operation); + } +} + #[derive(Component, Debug)] pub struct WaitingForInventoryOpen;