mirror of
https://github.com/mat-1/azalea.git
synced 2025-08-02 14:26:04 +00:00
fix issues when pathfinding to non-full blocks and add Client::view_inventory
This commit is contained in:
parent
7517a207db
commit
f3a5e91a8c
7 changed files with 37 additions and 19 deletions
|
@ -342,13 +342,13 @@ impl Client {
|
||||||
/// ```
|
/// ```
|
||||||
/// # use azalea_client::{Client, mining::Mining};
|
/// # use azalea_client::{Client, mining::Mining};
|
||||||
/// # fn example(bot: &Client) {
|
/// # fn example(bot: &Client) {
|
||||||
/// let is_mining = bot.map_get_component::<Mining, _>(|m| m.is_some());
|
/// let is_mining = bot.map_get_component::<Mining, _>(|m| m).is_some();
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn map_get_component<T: Component, R>(&self, f: impl FnOnce(Option<&T>) -> R) -> R {
|
pub fn map_get_component<T: Component, R>(&self, f: impl FnOnce(&T) -> R) -> Option<R> {
|
||||||
let mut ecs = self.ecs.lock();
|
let mut ecs = self.ecs.lock();
|
||||||
let value = self.query::<Option<&T>>(&mut ecs);
|
let value = self.query::<Option<&T>>(&mut ecs);
|
||||||
f(value)
|
value.map(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an `RwLock` with a reference to our (potentially shared) world.
|
/// Get an `RwLock` with a reference to our (potentially shared) world.
|
||||||
|
|
|
@ -95,8 +95,7 @@ impl Client {
|
||||||
/// A component present on all local players that have an inventory.
|
/// A component present on all local players that have an inventory.
|
||||||
#[derive(Component, Debug, Clone)]
|
#[derive(Component, Debug, Clone)]
|
||||||
pub struct Inventory {
|
pub struct Inventory {
|
||||||
/// A component that contains the player's inventory menu. This is
|
/// The player's inventory menu. This is guaranteed to be a `Menu::Player`.
|
||||||
/// guaranteed to be a `Menu::Player`.
|
|
||||||
///
|
///
|
||||||
/// We keep it as a [`Menu`] since `Menu` has some useful functions that
|
/// We keep it as a [`Menu`] since `Menu` has some useful functions that
|
||||||
/// bare [`azalea_inventory::Player`] doesn't have.
|
/// bare [`azalea_inventory::Player`] doesn't have.
|
||||||
|
|
|
@ -335,8 +335,9 @@ impl Vec3 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The coordinates of a block in the world. For entities (if the coordinate
|
/// The coordinates of a block in the world.
|
||||||
/// have decimals), use [`Vec3`] instead.
|
///
|
||||||
|
/// For entities (if the coordinates are floating-point), use [`Vec3`] instead.
|
||||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
pub struct BlockPos {
|
pub struct BlockPos {
|
||||||
|
|
|
@ -41,6 +41,9 @@ pub struct PartialChunkStorage {
|
||||||
/// A storage for chunks where they're only stored weakly, so if they're not
|
/// A storage for chunks where they're only stored weakly, so if they're not
|
||||||
/// actively being used somewhere else they'll be forgotten. This is used for
|
/// actively being used somewhere else they'll be forgotten. This is used for
|
||||||
/// shared worlds.
|
/// shared worlds.
|
||||||
|
///
|
||||||
|
/// This is relatively cheap to clone since it's just an `IntMap` with `Weak`
|
||||||
|
/// pointers.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ChunkStorage {
|
pub struct ChunkStorage {
|
||||||
pub height: u32,
|
pub height: u32,
|
||||||
|
|
|
@ -32,6 +32,7 @@ pub trait ContainerClientExt {
|
||||||
fn open_inventory(&self) -> Option<ContainerHandle>;
|
fn open_inventory(&self) -> Option<ContainerHandle>;
|
||||||
fn get_held_item(&self) -> ItemStack;
|
fn get_held_item(&self) -> ItemStack;
|
||||||
fn get_open_container(&self) -> Option<ContainerHandleRef>;
|
fn get_open_container(&self) -> Option<ContainerHandleRef>;
|
||||||
|
fn view_inventory(&self) -> Menu;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContainerClientExt for Client {
|
impl ContainerClientExt for Client {
|
||||||
|
@ -100,9 +101,8 @@ impl ContainerClientExt for Client {
|
||||||
/// Get the item in the bot's hotbar that is currently being held in its
|
/// Get the item in the bot's hotbar that is currently being held in its
|
||||||
/// main hand.
|
/// main hand.
|
||||||
fn get_held_item(&self) -> ItemStack {
|
fn get_held_item(&self) -> ItemStack {
|
||||||
let ecs = self.ecs.lock();
|
self.map_get_component::<Inventory, _>(|inventory| inventory.held_item())
|
||||||
let inventory = ecs.get::<Inventory>(self.entity).expect("no inventory");
|
.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
|
||||||
|
@ -123,6 +123,15 @@ impl ContainerClientExt for Client {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the player's inventory menu.
|
||||||
|
///
|
||||||
|
/// This is a shortcut for accessing the client's
|
||||||
|
/// [`Inventory::inventory_menu`].
|
||||||
|
fn view_inventory(&self) -> Menu {
|
||||||
|
self.map_get_component::<Inventory, _>(|inventory| inventory.inventory_menu.clone())
|
||||||
|
.expect("no inventory")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A handle to a container that may be open. This does not close the container
|
/// A handle to a container that may be open. This does not close the container
|
||||||
|
|
|
@ -29,7 +29,9 @@ impl Goal for BlockPosGoal {
|
||||||
xz_heuristic(dx, dz) + y_heuristic(dy)
|
xz_heuristic(dx, dz) + y_heuristic(dy)
|
||||||
}
|
}
|
||||||
fn success(&self, n: BlockPos) -> bool {
|
fn success(&self, n: BlockPos) -> bool {
|
||||||
n == self.0
|
// the second half of this condition is intended to fix issues when pathing to
|
||||||
|
// non-full blocks
|
||||||
|
n == self.0 || n.down(1) == self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,8 +221,8 @@ impl Goal for ReachBlockPosGoal {
|
||||||
}
|
}
|
||||||
fn success(&self, n: BlockPos) -> bool {
|
fn success(&self, n: BlockPos) -> bool {
|
||||||
// only do the expensive check if we're close enough
|
// only do the expensive check if we're close enough
|
||||||
let distance = (self.pos - n).length_squared();
|
let distance = self.pos.distance_squared_to(&n);
|
||||||
if distance > self.max_check_distance * self.max_check_distance {
|
if distance > self.max_check_distance.pow(2) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -274,10 +274,8 @@ impl PathfinderClientExt for azalea_client::Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_goto_target_reached(&self) -> bool {
|
fn is_goto_target_reached(&self) -> bool {
|
||||||
self.map_get_component::<Pathfinder, _>(|p| {
|
self.map_get_component::<Pathfinder, _>(|p| p.goal.is_none() && !p.is_calculating)
|
||||||
p.map(|p| p.goal.is_none() && !p.is_calculating)
|
.unwrap_or(true)
|
||||||
.unwrap_or(true)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -689,7 +687,12 @@ pub fn timeout_movement(
|
||||||
let world_lock = instance_container
|
let world_lock = instance_container
|
||||||
.get(instance_name)
|
.get(instance_name)
|
||||||
.expect("Entity tried to pathfind but the entity isn't in a valid world");
|
.expect("Entity tried to pathfind but the entity isn't in a valid world");
|
||||||
let successors_fn: moves::SuccessorsFn = pathfinder.successors_fn.unwrap();
|
let Some(successors_fn) = pathfinder.successors_fn else {
|
||||||
|
warn!(
|
||||||
|
"pathfinder was going to patch path because of timeout, but there was no successors_fn"
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let custom_state = custom_state.cloned().unwrap_or_default();
|
let custom_state = custom_state.cloned().unwrap_or_default();
|
||||||
|
|
||||||
|
@ -749,7 +752,8 @@ pub fn check_node_reached(
|
||||||
let z_difference_from_center = position.z - (movement.target.z as f64 + 0.5);
|
let z_difference_from_center = position.z - (movement.target.z as f64 + 0.5);
|
||||||
// this is to make sure we don't fall off immediately after finishing the path
|
// this is to make sure we don't fall off immediately after finishing the path
|
||||||
physics.on_ground()
|
physics.on_ground()
|
||||||
&& BlockPos::from(position) == movement.target
|
// 0.5 to handle non-full blocks
|
||||||
|
&& BlockPos::from(position.up(0.5)) == movement.target
|
||||||
// adding the delta like this isn't a perfect solution but it helps to make
|
// adding the delta like this isn't a perfect solution but it helps to make
|
||||||
// sure we don't keep going if our delta is high
|
// sure we don't keep going if our delta is high
|
||||||
&& (x_difference_from_center + physics.velocity.x).abs() < 0.2
|
&& (x_difference_from_center + physics.velocity.x).abs() < 0.2
|
||||||
|
|
Loading…
Add table
Reference in a new issue