mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 06:16:04 +00:00
replace wait_one_tick with wait_ticks and some other api improvements
This commit is contained in:
parent
04dd6dd0a4
commit
abf995a702
7 changed files with 102 additions and 21 deletions
|
@ -1,6 +1,7 @@
|
|||
use std::{
|
||||
collections::{HashSet, hash_set},
|
||||
ops::{Add, RangeInclusive},
|
||||
sync::LazyLock,
|
||||
};
|
||||
|
||||
use crate::{BlockState, block_state::BlockStateIntegerRepr};
|
||||
|
|
|
@ -60,6 +60,36 @@ impl Client {
|
|||
let inventory = self.query::<&Inventory>(&mut ecs);
|
||||
inventory.menu().clone()
|
||||
}
|
||||
|
||||
/// Returns the index of the hotbar slot that's currently selected.
|
||||
///
|
||||
/// If you want to access the actual held item, you can get the current menu
|
||||
/// with [`Client::menu`] and then get the slot index by offsetting from
|
||||
/// the start of [`azalea_inventory::Menu::hotbar_slots_range`].
|
||||
///
|
||||
/// You can use [`Self::set_selected_hotbar_slot`] to change it.
|
||||
pub fn selected_hotbar_slot(&self) -> u8 {
|
||||
let mut ecs = self.ecs.lock();
|
||||
let inventory = self.query::<&Inventory>(&mut ecs);
|
||||
inventory.selected_hotbar_slot
|
||||
}
|
||||
|
||||
/// Update the selected hotbar slot index.
|
||||
///
|
||||
/// This will run next `Update`, so you might want to call
|
||||
/// `bot.wait_updates(1)` after calling this if you're using `azalea`.
|
||||
pub fn set_selected_hotbar_slot(&self, new_hotbar_slot_index: u8) {
|
||||
assert!(
|
||||
new_hotbar_slot_index < 9,
|
||||
"Hotbar slot index must be in the range 0..=8"
|
||||
);
|
||||
|
||||
let mut ecs = self.ecs.lock();
|
||||
ecs.send_event(SetSelectedHotbarSlotEvent {
|
||||
entity: self.entity,
|
||||
slot: new_hotbar_slot_index,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// A component present on all local players that have an inventory.
|
||||
|
@ -499,7 +529,8 @@ impl Inventory {
|
|||
self.quick_craft_slots.clear();
|
||||
}
|
||||
|
||||
/// Get the item in the player's hotbar that is currently being held.
|
||||
/// Get the item in the player's hotbar that is currently being held in its
|
||||
/// main hand.
|
||||
pub fn held_item(&self) -> ItemStack {
|
||||
let inventory = &self.inventory_menu;
|
||||
let hotbar_items = &inventory.slots()[inventory.hotbar_slots_range()];
|
||||
|
|
|
@ -162,6 +162,16 @@ impl CardinalDirection {
|
|||
}
|
||||
}
|
||||
}
|
||||
impl From<CardinalDirection> for Direction {
|
||||
fn from(value: CardinalDirection) -> Self {
|
||||
match value {
|
||||
CardinalDirection::North => Direction::North,
|
||||
CardinalDirection::South => Direction::South,
|
||||
CardinalDirection::West => Direction::West,
|
||||
CardinalDirection::East => Direction::East,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Axis {
|
||||
/// Pick x, y, or z from the arguments depending on the axis.
|
||||
|
|
|
@ -61,6 +61,8 @@ impl From<QuickMoveClick> for ClickOperation {
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct SwapClick {
|
||||
pub source_slot: u16,
|
||||
/// 0-8 for hotbar slots, 40 for offhand, everything else is treated as a
|
||||
/// slot index.
|
||||
pub target_slot: u8,
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Add table
Reference in a new issue