mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 23:44:38 +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::{
|
use std::{
|
||||||
collections::{HashSet, hash_set},
|
collections::{HashSet, hash_set},
|
||||||
ops::{Add, RangeInclusive},
|
ops::{Add, RangeInclusive},
|
||||||
|
sync::LazyLock,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{BlockState, block_state::BlockStateIntegerRepr};
|
use crate::{BlockState, block_state::BlockStateIntegerRepr};
|
||||||
|
|
|
@ -60,6 +60,36 @@ impl Client {
|
||||||
let inventory = self.query::<&Inventory>(&mut ecs);
|
let inventory = self.query::<&Inventory>(&mut ecs);
|
||||||
inventory.menu().clone()
|
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.
|
/// A component present on all local players that have an inventory.
|
||||||
|
@ -499,7 +529,8 @@ impl Inventory {
|
||||||
self.quick_craft_slots.clear();
|
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 {
|
pub fn held_item(&self) -> ItemStack {
|
||||||
let inventory = &self.inventory_menu;
|
let inventory = &self.inventory_menu;
|
||||||
let hotbar_items = &inventory.slots()[inventory.hotbar_slots_range()];
|
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 {
|
impl Axis {
|
||||||
/// Pick x, y, or z from the arguments depending on the 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)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SwapClick {
|
pub struct SwapClick {
|
||||||
pub source_slot: u16,
|
pub source_slot: u16,
|
||||||
|
/// 0-8 for hotbar slots, 40 for offhand, everything else is treated as a
|
||||||
|
/// slot index.
|
||||||
pub target_slot: u8,
|
pub target_slot: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,10 +92,10 @@ pub trait BotClientExt {
|
||||||
fn get_tick_broadcaster(&self) -> tokio::sync::broadcast::Receiver<()>;
|
fn get_tick_broadcaster(&self) -> tokio::sync::broadcast::Receiver<()>;
|
||||||
/// Get a receiver that will receive a message every ECS Update.
|
/// Get a receiver that will receive a message every ECS Update.
|
||||||
fn get_update_broadcaster(&self) -> tokio::sync::broadcast::Receiver<()>;
|
fn get_update_broadcaster(&self) -> tokio::sync::broadcast::Receiver<()>;
|
||||||
/// Wait for one tick.
|
/// Wait for the specified number of game ticks.
|
||||||
fn wait_one_tick(&self) -> impl Future<Output = ()> + Send;
|
fn wait_ticks(&self, n: usize) -> impl Future<Output = ()> + Send;
|
||||||
/// Wait for one ECS Update.
|
/// Wait for the specified number of ECS `Update`s.
|
||||||
fn wait_one_update(&self) -> impl Future<Output = ()> + Send;
|
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
|
/// 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`].
|
/// 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()
|
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
|
/// 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.
|
/// instead and use the `Receiver` from it to avoid accidentally skipping
|
||||||
async fn wait_one_tick(&self) {
|
/// ticks and having to wait longer.
|
||||||
|
async fn wait_ticks(&self, n: usize) {
|
||||||
let mut receiver = self.get_tick_broadcaster();
|
let mut receiver = self.get_tick_broadcaster();
|
||||||
// wait for the next tick
|
for _ in 0..n {
|
||||||
let _ = receiver.recv().await;
|
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
|
/// 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.
|
/// instead and use the `Receiver` from it to avoid accidentally skipping
|
||||||
async fn wait_one_update(&self) {
|
/// ticks and having to wait longer.
|
||||||
|
async fn wait_updates(&self, n: usize) {
|
||||||
let mut receiver = self.get_update_broadcaster();
|
let mut receiver = self.get_update_broadcaster();
|
||||||
// wait for the next tick
|
for _ in 0..n {
|
||||||
let _ = receiver.recv().await;
|
let _ = receiver.recv().await;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn mine(&self, position: BlockPos) {
|
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) {
|
if let Ok((position, eye_height, mut look_direction)) = query.get_mut(event.entity) {
|
||||||
let new_look_direction =
|
let new_look_direction =
|
||||||
direction_looking_at(&position.up(eye_height.into()), &event.position);
|
direction_looking_at(&position.up(eye_height.into()), &event.position);
|
||||||
trace!(
|
trace!("look at {} (currently at {})", event.position, **position);
|
||||||
"look at {:?} (currently at {:?})",
|
|
||||||
event.position, **position
|
|
||||||
);
|
|
||||||
*look_direction = new_look_direction;
|
*look_direction = new_look_direction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,10 @@ use azalea_client::{
|
||||||
packet::game::ReceiveGamePacketEvent,
|
packet::game::ReceiveGamePacketEvent,
|
||||||
};
|
};
|
||||||
use azalea_core::position::BlockPos;
|
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 azalea_protocol::packets::game::ClientboundGamePacket;
|
||||||
use bevy_app::{App, Plugin, Update};
|
use bevy_app::{App, Plugin, Update};
|
||||||
use bevy_ecs::{component::Component, prelude::EventReader, system::Commands};
|
use bevy_ecs::{component::Component, prelude::EventReader, system::Commands};
|
||||||
|
@ -27,6 +30,7 @@ pub trait ContainerClientExt {
|
||||||
pos: BlockPos,
|
pos: BlockPos,
|
||||||
) -> impl Future<Output = Option<ContainerHandle>> + Send;
|
) -> impl Future<Output = Option<ContainerHandle>> + Send;
|
||||||
fn open_inventory(&self) -> Option<ContainerHandle>;
|
fn open_inventory(&self) -> Option<ContainerHandle>;
|
||||||
|
fn get_held_item(&self) -> ItemStack;
|
||||||
fn get_open_container(&self) -> Option<ContainerHandleRef>;
|
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
|
/// 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.
|
/// 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>) {
|
pub fn click(&self, operation: impl Into<ClickOperation>) {
|
||||||
self.0.click(operation);
|
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)]
|
#[derive(Component, Debug)]
|
||||||
|
|
|
@ -260,7 +260,7 @@ impl PathfinderClientExt for azalea_client::Client {
|
||||||
async fn wait_until_goto_target_reached(&self) {
|
async fn wait_until_goto_target_reached(&self) {
|
||||||
// we do this to make sure the event got handled before we start checking
|
// we do this to make sure the event got handled before we start checking
|
||||||
// is_goto_target_reached
|
// is_goto_target_reached
|
||||||
self.wait_one_update().await;
|
self.wait_updates(1).await;
|
||||||
|
|
||||||
let mut tick_broadcaster = self.get_tick_broadcaster();
|
let mut tick_broadcaster = self.get_tick_broadcaster();
|
||||||
while !self.is_goto_target_reached() {
|
while !self.is_goto_target_reached() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue