From ee5d3b298aa5325b619d07e6eadece1099072d8e Mon Sep 17 00:00:00 2001 From: mat Date: Sun, 12 Oct 2025 16:14:00 -1000 Subject: add optional timeout for opening containers --- CHANGELOG.md | 1 + azalea/src/container.rs | 49 +++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 649a23f1..c3d9c00c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ is breaking anyways, semantic versioning is not followed. - `Client::query`, `map_component`, and `map_get_component` were replaced by `Client::query_self`. - Rename `SendPacketEvent` to `SendGamePacketEvent` and `PingEvent` to `GamePingEvent`. - Swap the order of the type parameters in entity filtering functions so query is first, then filter. +- Add `timeout_ticks` field to `Client::open_container_at`. ### Fixed diff --git a/azalea/src/container.rs b/azalea/src/container.rs index 57753cc3..2394551b 100644 --- a/azalea/src/container.rs +++ b/azalea/src/container.rs @@ -31,6 +31,11 @@ pub trait ContainerClientExt { /// /// Use [`Client::open_inventory`] to open your own inventory. /// + /// `timeout_ticks` indicates how long the client will wait before giving + /// up and returning `None`. You may need to adjust it based on latency. + /// Setting the timeout to `None` will result in waiting potentially + /// forever. + /// /// ``` /// # use azalea::prelude::*; /// # async fn example(mut bot: azalea::Client) { @@ -48,7 +53,20 @@ pub trait ContainerClientExt { fn open_container_at( &self, pos: BlockPos, + timeout_ticks: Option, + ) -> impl Future> + Send; + + /// Wait until a container is open, up to the specified number of ticks. + /// + /// Returns `None` if the container was immediately opened and closed, or if + /// the timeout expires. + /// + /// If `timeout_ticks` is None, there will be no timeout. + fn wait_for_container_open( + &self, + timeout_ticks: Option, ) -> impl Future> + Send; + /// Open the player's inventory. /// /// This will return None if another container is open. @@ -79,17 +97,16 @@ pub trait ContainerClientExt { } impl ContainerClientExt for Client { - async fn open_container_at(&self, pos: BlockPos) -> Option { + async fn open_container_at( + &self, + pos: BlockPos, + timeout_ticks: Option, + ) -> Option { let mut ticks = self.get_tick_broadcaster(); // wait until it's not air (up to 10 ticks) for _ in 0..10 { - if !self - .world() - .read() - .get_block_state(pos) - .unwrap_or_default() - .is_collision_shape_empty() - { + let block = self.world().read().get_block_state(pos).unwrap_or_default(); + if !block.is_collision_shape_empty() { break; } let _ = ticks.recv().await; @@ -101,11 +118,27 @@ impl ContainerClientExt for Client { .insert(WaitingForInventoryOpen); self.block_interact(pos); + self.wait_for_container_open(timeout_ticks).await + } + + async fn wait_for_container_open( + &self, + timeout_ticks: Option, + ) -> Option { + let mut ticks = self.get_tick_broadcaster(); + let mut elapsed_ticks = 0; while ticks.recv().await.is_ok() { let ecs = self.ecs.lock(); if ecs.get::(self.entity).is_none() { break; } + + elapsed_ticks += 1; + if let Some(timeout_ticks) = timeout_ticks { + if elapsed_ticks >= timeout_ticks { + return None; + } + } } let ecs = self.ecs.lock(); -- cgit v1.2.3