aboutsummaryrefslogtreecommitdiff
path: root/azalea
diff options
context:
space:
mode:
authormat <git@matdoes.dev>2025-06-03 03:48:36 +0500
committermat <git@matdoes.dev>2025-06-03 03:48:36 +0500
commitabf995a70245028f9cc860ee231dc671f14adfcc (patch)
tree3e6052c028c409e4bc7279dbd2e6bcc6bed63748 /azalea
parent04dd6dd0a44faa760906bd60c9861a1b06a664a1 (diff)
downloadazalea-drasl-abf995a70245028f9cc860ee231dc671f14adfcc.tar.xz
replace wait_one_tick with wait_ticks and some other api improvements
Diffstat (limited to 'azalea')
-rw-r--r--azalea/src/bot.rs42
-rw-r--r--azalea/src/container.rs33
-rw-r--r--azalea/src/pathfinder/mod.rs2
3 files changed, 57 insertions, 20 deletions
diff --git a/azalea/src/bot.rs b/azalea/src/bot.rs
index 8bc9d594..9e8566bf 100644
--- a/azalea/src/bot.rs
+++ b/azalea/src/bot.rs
@@ -92,10 +92,10 @@ pub trait BotClientExt {
fn get_tick_broadcaster(&self) -> tokio::sync::broadcast::Receiver<()>;
/// Get a receiver that will receive a message every ECS Update.
fn get_update_broadcaster(&self) -> tokio::sync::broadcast::Receiver<()>;
- /// Wait for one tick.
- fn wait_one_tick(&self) -> impl Future<Output = ()> + Send;
- /// Wait for one ECS Update.
- fn wait_one_update(&self) -> impl Future<Output = ()> + Send;
+ /// Wait for the specified number of game ticks.
+ fn wait_ticks(&self, n: usize) -> impl Future<Output = ()> + Send;
+ /// Wait for the specified number of ECS `Update`s.
+ fn wait_updates(&self, n: usize) -> impl Future<Output = ()> + Send;
/// Mine a block. This won't turn the bot's head towards the block, so if
/// that's necessary you'll have to do that yourself with [`look_at`].
///
@@ -156,23 +156,32 @@ impl BotClientExt for azalea_client::Client {
update_broadcast.subscribe()
}
- /// Wait for one tick using [`Self::get_tick_broadcaster`].
+ /// Wait for the specified number of ticks using
+ /// [`Self::get_tick_broadcaster`].
///
/// If you're going to run this in a loop, you may want to use that function
- /// instead and use the `Receiver` from it as it'll be more efficient.
- async fn wait_one_tick(&self) {
+ /// instead and use the `Receiver` from it to avoid accidentally skipping
+ /// ticks and having to wait longer.
+ async fn wait_ticks(&self, n: usize) {
let mut receiver = self.get_tick_broadcaster();
- // wait for the next tick
- let _ = receiver.recv().await;
+ for _ in 0..n {
+ let _ = receiver.recv().await;
+ }
}
- /// Waits for one ECS Update using [`Self::get_update_broadcaster`].
+ /// Waits for the specified number of ECS `Update`s using
+ /// [`Self::get_update_broadcaster`].
+ ///
+ /// These are basically equivalent to frames because even though we have no
+ /// rendering, some game mechanics depend on frames.
///
/// If you're going to run this in a loop, you may want to use that function
- /// instead and use the `Receiver` from it as it'll be more efficient.
- async fn wait_one_update(&self) {
+ /// instead and use the `Receiver` from it to avoid accidentally skipping
+ /// ticks and having to wait longer.
+ async fn wait_updates(&self, n: usize) {
let mut receiver = self.get_update_broadcaster();
- // wait for the next tick
- let _ = receiver.recv().await;
+ for _ in 0..n {
+ let _ = receiver.recv().await;
+ }
}
async fn mine(&self, position: BlockPos) {
@@ -221,10 +230,7 @@ fn look_at_listener(
if let Ok((position, eye_height, mut look_direction)) = query.get_mut(event.entity) {
let new_look_direction =
direction_looking_at(&position.up(eye_height.into()), &event.position);
- trace!(
- "look at {:?} (currently at {:?})",
- event.position, **position
- );
+ trace!("look at {} (currently at {})", event.position, **position);
*look_direction = new_look_direction;
}
}
diff --git a/azalea/src/container.rs b/azalea/src/container.rs
index 6715cd63..e5896d8a 100644
--- a/azalea/src/container.rs
+++ b/azalea/src/container.rs
@@ -6,7 +6,10 @@ use azalea_client::{
packet::game::ReceiveGamePacketEvent,
};
use azalea_core::position::BlockPos;
-use azalea_inventory::{ItemStack, Menu, operations::ClickOperation};
+use azalea_inventory::{
+ ItemStack, Menu,
+ operations::{ClickOperation, PickupClick, QuickMoveClick},
+};
use azalea_protocol::packets::game::ClientboundGamePacket;
use bevy_app::{App, Plugin, Update};
use bevy_ecs::{component::Component, prelude::EventReader, system::Commands};
@@ -27,6 +30,7 @@ pub trait ContainerClientExt {
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>;
}
@@ -93,6 +97,14 @@ impl ContainerClientExt for Client {
}
}
+ /// Get the item in the bot's hotbar that is currently being held in its
+ /// main hand.
+ fn get_held_item(&self) -> ItemStack {
+ let ecs = self.ecs.lock();
+ let inventory = ecs.get::<Inventory>(self.entity).expect("no inventory");
+ inventory.held_item()
+ }
+
/// 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.
///
@@ -228,6 +240,25 @@ impl ContainerHandle {
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)]
diff --git a/azalea/src/pathfinder/mod.rs b/azalea/src/pathfinder/mod.rs
index 08c72f9a..5ee56643 100644
--- a/azalea/src/pathfinder/mod.rs
+++ b/azalea/src/pathfinder/mod.rs
@@ -260,7 +260,7 @@ impl PathfinderClientExt for azalea_client::Client {
async fn wait_until_goto_target_reached(&self) {
// we do this to make sure the event got handled before we start checking
// is_goto_target_reached
- self.wait_one_update().await;
+ self.wait_updates(1).await;
let mut tick_broadcaster = self.get_tick_broadcaster();
while !self.is_goto_target_reached() {