aboutsummaryrefslogtreecommitdiff
path: root/azalea/src/client_impl
diff options
context:
space:
mode:
Diffstat (limited to 'azalea/src/client_impl')
-rw-r--r--azalea/src/client_impl/entity_query.rs106
-rw-r--r--azalea/src/client_impl/mod.rs120
2 files changed, 101 insertions, 125 deletions
diff --git a/azalea/src/client_impl/entity_query.rs b/azalea/src/client_impl/entity_query.rs
index 683d755e..8de48478 100644
--- a/azalea/src/client_impl/entity_query.rs
+++ b/azalea/src/client_impl/entity_query.rs
@@ -11,7 +11,7 @@ use bevy_ecs::{
};
use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard};
-use crate::Client;
+use crate::{Client, entity_ref::EntityRef};
impl Client {
/// Get a component from the client.
@@ -117,7 +117,7 @@ impl Client {
) -> R {
self.try_query_entity(entity, f).unwrap_or_else(|_| {
panic!(
- "Entity is missing a required component {:?}",
+ "Querying entity {entity} failed when getting {:?}",
any::type_name::<D>()
)
})
@@ -138,40 +138,44 @@ impl Client {
qs.get_mut(&mut ecs, entity).map(f)
}
+ /// Quickly returns an [`EntityRef`] for an arbitrary entity that
+ /// matches the given predicate function that is in the same
+ /// [`Instance`] as the client.
+ ///
+ /// [`Instance`]: azalea_world::Instance
+ pub fn any_entity_by<Q: QueryData, F: QueryFilter>(
+ &self,
+ predicate: impl EntityPredicate<Q, F>,
+ ) -> Option<EntityRef> {
+ self.any_entity_id_by(predicate)
+ .map(|e| self.entity_ref_for(e))
+ }
/// Quickly returns 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.
+ /// To get an [`EntityRef`], consider using [`Self::any_entity_by`]
+ /// instead.
///
/// If you want to find the nearest entity, consider using
- /// [`Self::nearest_entity_by`] instead. If you want to find all entities
- /// that match the predicate, use [`Self::nearest_entities_by`].
+ /// [`Self::nearest_entity_id_by`] instead. If you want to find all entities
+ /// that match the predicate, use [`Self::nearest_entity_ids_by`].
///
/// # Example
+ ///
/// ```
- /// use azalea::{
- /// Client,
- /// entity::{Position, metadata::Player},
- /// player::GameProfileComponent,
- /// };
+ /// use azalea::{entity::metadata::Player, player::GameProfileComponent};
/// use bevy_ecs::query::With;
///
- /// # fn example(mut bot: Client, sender_name: String) {
- /// let entity = bot.any_entity_by::<&GameProfileComponent, With<Player>>(
+ /// # fn example(mut bot: azalea::Client, sender_name: String) {
+ /// let entity = bot.any_entity_id_by::<&GameProfileComponent, With<Player>>(
/// |profile: &GameProfileComponent| profile.name == sender_name,
/// );
- /// if let Some(entity) = entity {
- /// let position = bot.entity_component::<Position>(entity);
- /// // ...
- /// }
/// # }
/// ```
///
- /// [`Entity`]: bevy_ecs::entity::Entity
/// [`Instance`]: azalea_world::Instance
- pub fn any_entity_by<Q: QueryData, F: QueryFilter>(
+ pub fn any_entity_id_by<Q: QueryData, F: QueryFilter>(
&self,
predicate: impl EntityPredicate<Q, F>,
) -> Option<Entity> {
@@ -179,43 +183,59 @@ impl Client {
predicate.find_any(self.ecs.clone(), &instance_name)
}
- /// Return a lightweight [`Entity`] for the nearest entity that matches the
+ /// Return an [`EntityRef`] for the nearest entity that matches the
/// given predicate function.
///
- /// You can then use [`Self::entity_component`] to get components from this
- /// entity.
- ///
/// If you don't need the entity to be the nearest one, it may be more
/// efficient to use [`Self::any_entity_by`] instead. You can also use
/// [`Self::nearest_entities_by`] to get all nearby entities.
///
- /// ```
- /// use azalea_entity::{LocalEntity, Position, metadata::Player};
- /// use bevy_ecs::query::{With, Without};
+ /// Also see [`Self::nearest_entity_id_by`] if you only need the lightweight
+ /// [`Entity`] identifier.
+ pub fn nearest_entity_by<Q: QueryData, F: QueryFilter>(
+ &self,
+ predicate: impl EntityPredicate<Q, F>,
+ ) -> Option<EntityRef> {
+ self.nearest_entity_id_by(predicate)
+ .map(|e| self.entity_ref_for(e))
+ }
+ /// Return a lightweight [`Entity`] for the nearest entity that matches the
+ /// given predicate function.
///
- /// # fn example(mut bot: azalea::Client, sender_name: String) {
- /// // get the position of the nearest player
- /// if let Some(nearest_player) =
- /// bot.nearest_entity_by::<(), (With<Player>, Without<LocalEntity>)>(|_: ()| true)
- /// {
- /// let nearest_player_pos = **bot.entity_component::<Position>(nearest_player);
- /// bot.chat(format!("You are at {nearest_player_pos}"));
- /// }
- /// # }
- /// ```
+ /// To get an [`EntityRef`], consider using [`Self::nearest_entity_by`]
+ /// instead.
///
- /// [`Entity`]: bevy_ecs::entity::Entity
- pub fn nearest_entity_by<Q: QueryData, F: QueryFilter>(
+ /// If you don't need the entity to be the nearest one, it may be more
+ /// efficient to use [`Self::any_entity_id_by`] instead. You can also use
+ /// [`Self::nearest_entity_ids_by`] to get all nearby entities.
+ pub fn nearest_entity_id_by<Q: QueryData, F: QueryFilter>(
&self,
predicate: impl EntityPredicate<Q, F>,
) -> Option<Entity> {
- self.nearest_entities_by(predicate).first().copied()
+ self.nearest_entity_ids_by(predicate).first().copied()
}
- /// Similar to [`Self::nearest_entity_by`] but returns a `Vec<Entity>` of
- /// all entities in our instance that match the predicate.
+ /// Returns an array of all [`EntityRef`]s in the instance that match the
+ /// predicate, sorted by nearest first.
+ ///
+ /// To only get the nearest entity, consider using
+ /// [`Self::nearest_entity_by`]. If you only need the [`Entity`]
+ /// identifiers, you can use [`Self::nearest_entity_ids_by`] instead.
+ pub fn nearest_entities_by<Q: QueryData, F: QueryFilter>(
+ &self,
+ predicate: impl EntityPredicate<Q, F>,
+ ) -> Box<[EntityRef]> {
+ self.nearest_entity_ids_by(predicate)
+ .into_iter()
+ .map(|e| self.entity_ref_for(e))
+ .collect()
+ }
+ /// Returns an array of all [`Entity`]s in the instance that match the
+ /// predicate, sorted by nearest first.
///
- /// The first entity is the nearest one.
+ /// To only get the nearest entity, consider using
+ /// [`Self::nearest_entity_id_by`]. To get the [`EntityRef`]s instead, you
+ /// can use [`Self::nearest_entities_by`].
///
/// ```
/// # use azalea_entity::{LocalEntity, Position, metadata::Player};
@@ -225,7 +245,7 @@ impl Client {
/// bot.nearest_entities_by::<(), (With<Player>, Without<LocalEntity>)>(|_: ()| true);
/// # }
/// ```
- pub fn nearest_entities_by<Q: QueryData, F: QueryFilter>(
+ pub fn nearest_entity_ids_by<Q: QueryData, F: QueryFilter>(
&self,
predicate: impl EntityPredicate<Q, F>,
) -> Box<[Entity]> {
diff --git a/azalea/src/client_impl/mod.rs b/azalea/src/client_impl/mod.rs
index 419fc27e..e3876f2e 100644
--- a/azalea/src/client_impl/mod.rs
+++ b/azalea/src/client_impl/mod.rs
@@ -11,16 +11,8 @@ use azalea_client::{
player::{GameProfileComponent, PlayerInfo},
start_ecs_runner,
};
-use azalea_core::{
- data_registry::{DataRegistryWithKey, ResolvableDataRegistry},
- position::Vec3,
-};
-use azalea_entity::{
- Attributes, Position,
- dimensions::EntityDimensions,
- indexing::{EntityIdIndex, EntityUuidIndex},
- metadata::Health,
-};
+use azalea_core::data_registry::{DataRegistryWithKey, ResolvableDataRegistry};
+use azalea_entity::indexing::{EntityIdIndex, EntityUuidIndex};
use azalea_protocol::{
address::{ResolvableAddr, ResolvedAddr},
connect::Proxy,
@@ -39,7 +31,10 @@ use parking_lot::RwLock;
use tokio::sync::mpsc;
use uuid::Uuid;
-use crate::events::{Event, LocalPlayerEvents};
+use crate::{
+ entity_ref::EntityRef,
+ events::{Event, LocalPlayerEvents},
+};
pub mod attack;
pub mod chat;
@@ -309,47 +304,19 @@ impl Client {
self.query_self::<Option<&InstanceName>, _>(|ins| ins.is_some())
}
- /// Get the position of this client.
- ///
- /// This is a shortcut for `Vec3::from(&bot.component::<Position>())`.
- ///
- /// Note that this value is given a default of [`Vec3::ZERO`] when it
- /// receives the login packet, its true position may be set ticks
- /// later.
- pub fn position(&self) -> Vec3 {
- Vec3::from(
- &*self
- .get_component::<Position>()
- .expect("the client's position hasn't been initialized yet"),
- )
- }
-
- /// Get the bounding box dimensions for our client, which contains our
- /// width, height, and eye height.
- ///
- /// This is a shortcut for
- /// `self.component::<EntityDimensions>()`.
- pub fn dimensions(&self) -> EntityDimensions {
- self.component::<EntityDimensions>().clone()
- }
-
- /// Get the position of this client's eyes.
- ///
- /// This is a shortcut for
- /// `bot.position().up(bot.dimensions().eye_height)`.
- pub fn eye_position(&self) -> Vec3 {
- self.query_self::<(&Position, &EntityDimensions), _>(|(pos, dim)| {
- pos.up(dim.eye_height as f64)
- })
+ /// Returns the client as an [`EntityRef`], allowing you to treat it as any
+ /// other entity.
+ pub fn entity(&self) -> EntityRef {
+ self.entity_ref_for(self.entity)
}
- /// Get the health of this client.
- ///
- /// This is a shortcut for `*bot.component::<Health>()`.
- pub fn health(&self) -> f32 {
- **self.component::<Health>()
+ /// Create an [`EntityRef`] for the given ECS entity.
+ pub fn entity_ref_for(&self, entity: Entity) -> EntityRef {
+ EntityRef::new(self.clone(), entity)
}
+}
+impl Client {
/// Get the hunger level of this client, which includes both food and
/// saturation.
///
@@ -366,13 +333,6 @@ impl Client {
self.profile().name.to_owned()
}
- /// Get the Minecraft UUID of this client.
- ///
- /// This is a shortcut for `bot.component::<GameProfileComponent>().uuid`.
- pub fn uuid(&self) -> Uuid {
- self.profile().uuid
- }
-
/// Get a map of player UUIDs to their information in the tab list.
///
/// This is a shortcut for `*bot.component::<TabList>()`.
@@ -398,23 +358,6 @@ impl Client {
self.component::<Account>().clone()
}
- /// Returns the attribute values of our player, which can be used to
- /// determine things like our movement speed.
- pub fn attributes(&self) -> Attributes {
- // this *could* return a mapped read guard for performance but that rarely
- // matters and it's just easier for the user if it doesn't.
- self.component::<Attributes>().clone()
- }
-
- /// Get the name of the instance (world) that the bot is in.
- ///
- /// This can be used to check if the client is in the same world as another
- /// entity.
- #[doc(alias("world_name", "dimension_name"))]
- pub fn instance_name(&self) -> InstanceName {
- (*self.component::<InstanceName>()).clone()
- }
-
/// A convenience function to get the Minecraft Uuid of a player by their
/// username, if they're present in the tab list.
///
@@ -427,23 +370,36 @@ impl Client {
.map(|player| player.profile.uuid)
}
- /// Get an ECS `Entity` in the world by its Minecraft UUID, if it's within
+ /// Get an [`Entity`] in the world by its Minecraft UUID, if it's within
/// render distance.
- pub fn entity_by_uuid(&self, uuid: Uuid) -> Option<Entity> {
+ ///
+ /// Also see [`Self::entity_by_uuid`] and
+ /// [`Self::entity_id_by_minecraft_id`].
+ pub fn entity_id_by_uuid(&self, uuid: Uuid) -> Option<Entity> {
self.map_resource::<EntityUuidIndex, _>(|entity_uuid_index| entity_uuid_index.get(&uuid))
}
+ /// Get an [`EntityRef`] in the world by its Minecraft UUID, if it's within
+ /// render distance.
+ ///
+ /// Also see [`Self::entity_id_by_uuid`].
+ pub fn entity_by_uuid(&self, uuid: Uuid) -> Option<EntityRef> {
+ self.entity_id_by_uuid(uuid).map(|e| self.entity_ref_for(e))
+ }
- /// Convert an ECS `Entity` to a [`MinecraftEntityId`].
- pub fn minecraft_entity_by_ecs_entity(&self, entity: Entity) -> Option<MinecraftEntityId> {
+ /// Get an [`Entity`] in the world by its [`MinecraftEntityId`].
+ ///
+ /// Also see [`Self::entity_by_uuid`] and [`Self::entity_id_by_uuid`].
+ pub fn entity_id_by_minecraft_id(&self, id: MinecraftEntityId) -> Option<Entity> {
self.query_self::<&EntityIdIndex, _>(|entity_id_index| {
- entity_id_index.get_by_ecs_entity(entity)
+ entity_id_index.get_by_minecraft_entity(id)
})
}
- /// Convert a [`MinecraftEntityId`] to an ECS `Entity`.
- pub fn ecs_entity_by_minecraft_entity(&self, entity: MinecraftEntityId) -> Option<Entity> {
- self.query_self::<&EntityIdIndex, _>(|entity_id_index| {
- entity_id_index.get_by_minecraft_entity(entity)
- })
+ /// Get an [`EntityRef`] in the world by its [`MinecraftEntityId`].
+ ///
+ /// Also see [`Self::entity_id_by_uuid`].
+ pub fn entity_by_minecraft_id(&self, id: MinecraftEntityId) -> Option<EntityRef> {
+ self.entity_id_by_minecraft_id(id)
+ .map(|e| EntityRef::new(self.clone(), e))
}
/// Call the given function with the client's [`RegistryHolder`].