azalea_client/
entity_query.rs

1use std::{any, sync::Arc};
2
3use azalea_core::position::Vec3;
4use azalea_entity::Position;
5use azalea_world::InstanceName;
6use bevy_ecs::{
7    component::Component,
8    entity::Entity,
9    query::{QueryData, QueryEntityError, QueryFilter, QueryItem, ROQueryItem},
10    world::World,
11};
12use parking_lot::Mutex;
13
14use crate::Client;
15
16impl Client {
17    /// A convenience function for getting components from our client's entity.
18    ///
19    /// To query another entity, you can use [`Self::query_entity`].
20    ///
21    /// # Examples
22    /// ```
23    /// # use azalea_world::InstanceName;
24    /// # fn example(mut client: azalea_client::Client) {
25    /// let is_logged_in = client.query_self::<Option<&InstanceName>, _>(|ins| ins.is_some());
26    /// # }
27    /// ```
28    ///
29    /// # Panics
30    ///
31    /// This will panic if the component doesn't exist on the client.
32    pub fn query_self<D: QueryData, R>(&self, f: impl FnOnce(QueryItem<D>) -> R) -> R {
33        let mut ecs = self.ecs.lock();
34        let mut qs = ecs.query::<D>();
35        let res = qs.get_mut(&mut ecs, self.entity).unwrap_or_else(|_| {
36            panic!(
37                "Our client is missing a required component {:?}",
38                any::type_name::<D>()
39            )
40        });
41        f(res)
42    }
43
44    /// A convenience function for getting components from any entity.
45    ///
46    /// If you're querying the client, you should use [`Self::query_self`].
47    ///
48    /// # Panics
49    ///
50    /// This will panic if the entity doesn't exist or if the query isn't valid
51    /// for the entity. For a non-panicking version, you may use
52    /// [`Self::try_query_entity`].
53    pub fn query_entity<D: QueryData, R>(
54        &self,
55        entity: Entity,
56        f: impl FnOnce(QueryItem<D>) -> R,
57    ) -> R {
58        self.try_query_entity(entity, f).unwrap_or_else(|_| {
59            panic!(
60                "Entity is missing a required component {:?}",
61                any::type_name::<D>()
62            )
63        })
64    }
65
66    /// A convenience function for getting components from any entity, or None
67    /// if the query fails.
68    ///
69    /// If you're sure that the entity exists and that the query will succeed,
70    /// you can use [`Self::query_entity`].
71    pub fn try_query_entity<D: QueryData, R>(
72        &self,
73        entity: Entity,
74        f: impl FnOnce(QueryItem<D>) -> R,
75    ) -> Result<R, QueryEntityError> {
76        let mut ecs = self.ecs.lock();
77        let mut qs = ecs.query::<D>();
78        qs.get_mut(&mut ecs, entity).map(f)
79    }
80
81    /// Quickly returns a lightweight [`Entity`] for an arbitrary entity that
82    /// matches the given predicate function that is in the same
83    /// [`Instance`] as the client.
84    ///
85    /// You can then use [`Self::entity_component`] to get components from this
86    /// entity.
87    ///
88    /// If you want to find the nearest entity, consider using
89    /// [`Self::nearest_entity_by`] instead. If you want to find all entities
90    /// that match the predicate, use [`Self::nearest_entities_by`].
91    ///
92    /// # Example
93    /// ```
94    /// use azalea_client::{Client, player::GameProfileComponent};
95    /// use azalea_entity::{Position, metadata::Player};
96    /// use bevy_ecs::query::With;
97    ///
98    /// # fn example(mut bot: Client, sender_name: String) {
99    /// let entity = bot.any_entity_by::<&GameProfileComponent, With<Player>>(
100    ///     |profile: &GameProfileComponent| profile.name == sender_name,
101    /// );
102    /// if let Some(entity) = entity {
103    ///     let position = bot.entity_component::<Position>(entity);
104    ///     // ...
105    /// }
106    /// # }
107    /// ```
108    ///
109    /// [`Entity`]: bevy_ecs::entity::Entity
110    /// [`Instance`]: azalea_world::Instance
111    pub fn any_entity_by<Q: QueryData, F: QueryFilter>(
112        &self,
113        predicate: impl EntityPredicate<Q, F>,
114    ) -> Option<Entity> {
115        let instance_name = self.get_component::<InstanceName>()?;
116        predicate.find_any(self.ecs.clone(), &instance_name)
117    }
118
119    /// Return a lightweight [`Entity`] for the nearest entity that matches the
120    /// given predicate function.
121    ///
122    /// You can then use [`Self::entity_component`] to get components from this
123    /// entity.
124    ///
125    /// If you don't need the entity to be the nearest one, it may be more
126    /// efficient to use [`Self::any_entity_by`] instead. You can also use
127    /// [`Self::nearest_entities_by`] to get all nearby entities.
128    ///
129    /// ```
130    /// use azalea_entity::{LocalEntity, Position, metadata::Player};
131    /// use bevy_ecs::query::{With, Without};
132    ///
133    /// # fn example(mut bot: azalea_client::Client, sender_name: String) {
134    /// // get the position of the nearest player
135    /// if let Some(nearest_player) =
136    ///     bot.nearest_entity_by::<(), (With<Player>, Without<LocalEntity>)>(|_: ()| true)
137    /// {
138    ///     let nearest_player_pos = *bot.entity_component::<Position>(nearest_player);
139    ///     bot.chat(format!("You are at {nearest_player_pos}"));
140    /// }
141    /// # }
142    /// ```
143    ///
144    /// [`Entity`]: bevy_ecs::entity::Entity
145    pub fn nearest_entity_by<Q: QueryData, F: QueryFilter>(
146        &self,
147        predicate: impl EntityPredicate<Q, F>,
148    ) -> Option<Entity> {
149        self.nearest_entities_by(predicate).first().copied()
150    }
151
152    /// Similar to [`Self::nearest_entity_by`] but returns a `Vec<Entity>` of
153    /// all entities in our instance that match the predicate.
154    ///
155    /// The first entity is the nearest one.
156    ///
157    /// ```
158    /// # use azalea_entity::{LocalEntity, Position, metadata::Player};
159    /// # use bevy_ecs::query::{With, Without};
160    /// # fn example(mut bot: azalea_client::Client, sender_name: String) {
161    /// let nearby_players =
162    ///     bot.nearest_entities_by::<(), (With<Player>, Without<LocalEntity>)>(|_: ()| true);
163    /// # }
164    /// ```
165    pub fn nearest_entities_by<Q: QueryData, F: QueryFilter>(
166        &self,
167        predicate: impl EntityPredicate<Q, F>,
168    ) -> Vec<Entity> {
169        let Some(instance_name) = self.get_component::<InstanceName>() else {
170            return vec![];
171        };
172        let Some(position) = self.get_component::<Position>() else {
173            return vec![];
174        };
175        predicate.find_all_sorted(self.ecs.clone(), &instance_name, (&position).into())
176    }
177
178    /// Get a component from an entity.
179    ///
180    /// Note that this will return an owned type (i.e. not a reference) so it
181    /// may be expensive for larger types.
182    ///
183    /// If you're trying to get a component for this client, use
184    /// [`Self::component`].
185    pub fn entity_component<Q: Component + Clone>(&self, entity: Entity) -> Q {
186        let mut ecs = self.ecs.lock();
187        let mut q = ecs.query::<&Q>();
188        let components = q.get(&ecs, entity).unwrap_or_else(|_| {
189            panic!(
190                "Entity is missing a required component {:?}",
191                any::type_name::<Q>()
192            )
193        });
194        components.clone()
195    }
196
197    /// Get a component from an entity, if it exists.
198    ///
199    /// This is similar to [`Self::entity_component`] but returns an `Option`
200    /// instead of panicking if the component isn't present.
201    pub fn get_entity_component<Q: Component + Clone>(&self, entity: Entity) -> Option<Q> {
202        let mut ecs = self.ecs.lock();
203        let mut q = ecs.query::<&Q>();
204        let components = q.get(&ecs, entity).ok();
205        components.cloned()
206    }
207}
208
209pub trait EntityPredicate<Q: QueryData, Filter: QueryFilter> {
210    fn find_any(&self, ecs_lock: Arc<Mutex<World>>, instance_name: &InstanceName)
211    -> Option<Entity>;
212    fn find_all_sorted(
213        &self,
214        ecs_lock: Arc<Mutex<World>>,
215        instance_name: &InstanceName,
216        nearest_to: Vec3,
217    ) -> Vec<Entity>;
218}
219impl<F, Q: QueryData, Filter: QueryFilter> EntityPredicate<Q, Filter> for F
220where
221    F: Fn(ROQueryItem<Q>) -> bool,
222    for<'w, 's> <<Q as QueryData>::ReadOnly as QueryData>::Item<'w, 's>: Copy,
223{
224    fn find_any(
225        &self,
226        ecs_lock: Arc<Mutex<World>>,
227        instance_name: &InstanceName,
228    ) -> Option<Entity> {
229        let mut ecs = ecs_lock.lock();
230        let mut query = ecs.query_filtered::<(Entity, &InstanceName, Q), Filter>();
231        query
232            .iter(&ecs)
233            .find(|(_, e_instance_name, q)| *e_instance_name == instance_name && (self)(*q))
234            .map(|(e, _, _)| e)
235    }
236
237    fn find_all_sorted(
238        &self,
239        ecs_lock: Arc<Mutex<World>>,
240        instance_name: &InstanceName,
241        nearest_to: Vec3,
242    ) -> Vec<Entity> {
243        let mut ecs = ecs_lock.lock();
244        let mut query = ecs.query_filtered::<(Entity, &InstanceName, &Position, Q), Filter>();
245        let mut entities = query
246            .iter(&ecs)
247            .filter(|(_, e_instance_name, _, q)| *e_instance_name == instance_name && (self)(*q))
248            .map(|(e, _, position, _)| (e, Vec3::from(position)))
249            .collect::<Vec<(Entity, Vec3)>>();
250
251        entities.sort_by_cached_key(|(_, position)| {
252            // to_bits is fine here as long as the number is positive
253            position.distance_squared_to(nearest_to).to_bits()
254        });
255
256        entities
257            .into_iter()
258            .map(|(e, _)| e)
259            .collect::<Vec<Entity>>()
260    }
261}