diff --git a/azalea-client/src/entity_query.rs b/azalea-client/src/entity_query.rs index ad8a87a6..5b19bb24 100644 --- a/azalea-client/src/entity_query.rs +++ b/azalea-client/src/entity_query.rs @@ -1,5 +1,7 @@ use std::{any, sync::Arc}; +use azalea_core::position::Vec3; +use azalea_entity::Position; use azalea_world::InstanceName; use bevy_ecs::{ component::Component, @@ -34,13 +36,16 @@ impl Client { }) } - /// Return a lightweight [`Entity`] for the first entity that matches the + /// Return a lightweight [`Entity`] for an arbitrary entity that matches the /// given predicate function that is in the same [`Instance`] as the /// client. /// /// You can then use [`Self::entity_component`] to get components from this /// entity. /// + /// Also see [`Self::entities_by`] which will return all entities that match + /// the predicate and sorts them by distance (unlike `entity_by`). + /// /// # Example /// ``` /// use azalea_client::{Client, player::GameProfileComponent}; @@ -65,11 +70,14 @@ impl Client { predicate: impl EntityPredicate, ) -> Option { let instance_name = self.get_component::()?; - predicate.find(self.ecs.clone(), &instance_name) + predicate.find_any(self.ecs.clone(), &instance_name) } - /// Same as [`Self::entity_by`] but returns a `Vec` of all entities - /// in our instance that match the predicate. + /// Similar to [`Self::entity_by`] but returns a `Vec` of all + /// entities in our instance that match the predicate. + /// + /// Unlike `entity_by`, the result is sorted by distance to our client's + /// position, so the closest entity is first. pub fn entities_by( &self, predicate: impl EntityPredicate, @@ -77,7 +85,10 @@ impl Client { let Some(instance_name) = self.get_component::() else { return vec![]; }; - predicate.find_all(self.ecs.clone(), &instance_name) + let Some(position) = self.get_component::() else { + return vec![]; + }; + predicate.find_all_sorted(self.ecs.clone(), &instance_name, (&position).into()) } /// Get a component from an entity. Note that this will return an owned type @@ -109,14 +120,24 @@ impl Client { } pub trait EntityPredicate { - fn find(&self, ecs_lock: Arc>, instance_name: &InstanceName) -> Option; - fn find_all(&self, ecs_lock: Arc>, instance_name: &InstanceName) -> Vec; + fn find_any(&self, ecs_lock: Arc>, instance_name: &InstanceName) + -> Option; + fn find_all_sorted( + &self, + ecs_lock: Arc>, + instance_name: &InstanceName, + nearest_to: Vec3, + ) -> Vec; } impl EntityPredicate for F where F: Fn(&ROQueryItem) -> bool, { - fn find(&self, ecs_lock: Arc>, instance_name: &InstanceName) -> Option { + fn find_any( + &self, + ecs_lock: Arc>, + instance_name: &InstanceName, + ) -> Option { let mut ecs = ecs_lock.lock(); let mut query = ecs.query_filtered::<(Entity, &InstanceName, Q), Filter>(); query @@ -125,13 +146,28 @@ where .map(|(e, _, _)| e) } - fn find_all(&self, ecs_lock: Arc>, instance_name: &InstanceName) -> Vec { + fn find_all_sorted( + &self, + ecs_lock: Arc>, + instance_name: &InstanceName, + nearest_to: Vec3, + ) -> Vec { let mut ecs = ecs_lock.lock(); - let mut query = ecs.query_filtered::<(Entity, &InstanceName, Q), Filter>(); - query + let mut query = ecs.query_filtered::<(Entity, &InstanceName, &Position, Q), Filter>(); + let mut entities = query .iter(&ecs) - .filter(|(_, e_instance_name, q)| *e_instance_name == instance_name && (self)(q)) - .map(|(e, _, _)| e) - .collect::>() + .filter(|(_, e_instance_name, _, q)| *e_instance_name == instance_name && (self)(q)) + .map(|(e, _, position, _)| (e, Vec3::from(position))) + .collect::>(); + + entities.sort_by_cached_key(|(_, position)| { + // to_bits is fine here as long as the number is positive + position.distance_squared_to(&nearest_to).to_bits() + }); + + entities + .into_iter() + .map(|(e, _)| e) + .collect::>() } } diff --git a/azalea-client/src/plugins/mining.rs b/azalea-client/src/plugins/mining.rs index 8d466328..4f076129 100644 --- a/azalea-client/src/plugins/mining.rs +++ b/azalea-client/src/plugins/mining.rs @@ -8,7 +8,7 @@ use azalea_world::{InstanceContainer, InstanceName}; use bevy_app::{App, Plugin, Update}; use bevy_ecs::prelude::*; use derive_more::{Deref, DerefMut}; -use tracing::{info, trace}; +use tracing::trace; use crate::{ Client, diff --git a/azalea-entity/src/lib.rs b/azalea-entity/src/lib.rs index 44a4a9ee..ad225400 100644 --- a/azalea-entity/src/lib.rs +++ b/azalea-entity/src/lib.rs @@ -389,6 +389,8 @@ pub struct Dead; /// /// This is used to calculate the camera position for players, when spectating /// an entity, and when raycasting from the entity. +/// +/// The default eye height for a player is 1.62 blocks. #[derive(Component, Clone, Copy, Debug, PartialEq, Deref, DerefMut)] pub struct EyeHeight(f32); impl EyeHeight { diff --git a/azalea-registry/src/lib.rs b/azalea-registry/src/lib.rs index 56e20028..6fb089d2 100644 --- a/azalea-registry/src/lib.rs +++ b/azalea-registry/src/lib.rs @@ -1883,6 +1883,16 @@ enum IntProviderKind { } registry! { +/// Every type of item in the game. +/// +/// You might find it useful in some cases to check for categories of items +/// with [`azalea_registry::tags::items`](crate::tags::items), like this +/// +/// ``` +/// let item = azalea_registry::Item::OakLog; +/// let is_log = azalea_registry::tags::items::LOGS.contains(&item); +/// assert!(is_log); +/// ``` enum Item { Air => "minecraft:air", Stone => "minecraft:stone", diff --git a/azalea/src/pathfinder/world.rs b/azalea/src/pathfinder/world.rs index b77183e8..3ec95136 100644 --- a/azalea/src/pathfinder/world.rs +++ b/azalea/src/pathfinder/world.rs @@ -551,6 +551,16 @@ pub fn is_block_state_passable(block: BlockState) -> bool { return false; } + if registry_block == azalea_registry::Block::PowderSnow { + // we can't jump out of powder snow + return false; + } + + if registry_block == azalea_registry::Block::SweetBerryBush { + // these hurt us + return false; + } + true }