azalea/client_impl/entity_query.rs
1use std::{any, sync::Arc};
2
3use azalea_core::position::Vec3;
4use azalea_entity::Position;
5use azalea_world::WorldName;
6use bevy_ecs::{
7 component::Component,
8 entity::Entity,
9 query::{QueryData, QueryEntityError, QueryFilter, QueryItem, ROQueryItem},
10 world::World,
11};
12use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard};
13
14use crate::{Client, entity_ref::EntityRef};
15
16impl Client {
17 /// Get a component from the client.
18 ///
19 /// This allows you to access certain data stored about the client entity
20 /// that isn't accessible in a simpler way.
21 ///
22 /// This returns a reference to the component wrapped by a read guard. This
23 /// makes the component cheap to access, but means that the ECS cannot be
24 /// mutated while it's in scope (it will cause a deadlock). In some cases,
25 /// it may be simpler for you to immediately clone the component after
26 /// accessing it.
27 ///
28 /// If the component isn't guaranteed to be present, consider using
29 /// [`Self::get_component`] instead.
30 ///
31 /// To do more complex queries or to mutate data, see [`Self::query_self`].
32 ///
33 /// To access data about other entities, you can use
34 /// [`Self::entity_component`] (and its other related functions).
35 ///
36 /// You may also use [`Self::ecs`] directly if you need more control over
37 /// when the ECS is locked.
38 ///
39 /// # Panics
40 ///
41 /// This will panic if the component doesn't exist on the client. Use
42 /// [`Self::get_component`] to avoid this.
43 ///
44 /// # Examples
45 ///
46 /// ```
47 /// # use azalea_world::WorldName;
48 /// # fn example(client: &azalea::Client) {
49 /// let world_name = client.component::<WorldName>();
50 /// # }
51 pub fn component<T: Component>(&self) -> MappedRwLockReadGuard<'_, T> {
52 self.get_component::<T>().unwrap_or_else(|| {
53 panic!(
54 "Our client is missing a required component: {:?}",
55 any::type_name::<&T>()
56 )
57 })
58 }
59
60 /// Get a component on this client, or `None` if it doesn't exist.
61 ///
62 /// If the component is guaranteed to be present, consider using
63 /// [`Self::component`]. Also see that function for more details.
64 pub fn get_component<T: Component>(&self) -> Option<MappedRwLockReadGuard<'_, T>> {
65 self.get_entity_component::<T>(self.entity)
66 }
67
68 /// Query the ECS for data from our client entity.
69 ///
70 /// To query another entity, you can use [`Self::query_entity`].
71 ///
72 /// You can use this to mutate data on the client.
73 ///
74 /// # Examples
75 ///
76 /// ```
77 /// # use azalea_entity::Position;
78 /// # fn example(mut client: azalea::Client) {
79 /// // teleport one block up
80 /// client.query_self::<&mut Position, _>(|mut pos| pos.y += 1.0);
81 /// # }
82 /// ```
83 ///
84 /// # Panics
85 ///
86 /// This will panic if the client is missing a component required by the
87 /// query. Consider using [`Self::try_query_self`] to avoid this.
88 pub fn query_self<D: QueryData, R>(&self, f: impl FnOnce(QueryItem<D>) -> R) -> R {
89 self.try_query_self::<D, R>(f).unwrap_or_else(|_| {
90 panic!(
91 "`Client::query_self` failed when querying for {:?}",
92 any::type_name::<D>()
93 )
94 })
95 }
96
97 /// Query the ECS for data from our client entity, or return `None` if the
98 /// query failed.
99 ///
100 /// Also see [`Self::query_self`].
101 pub fn try_query_self<D: QueryData, R>(
102 &self,
103 f: impl FnOnce(QueryItem<D>) -> R,
104 ) -> Result<R, QueryEntityError> {
105 let mut ecs = self.ecs.write();
106 let mut qs = ecs.query::<D>();
107 qs.get_mut(&mut ecs, self.entity).map(f)
108 }
109
110 /// Query the ECS for data from an entity.
111 ///
112 /// Note that it is often simpler to use [`Self::entity_component`].
113 ///
114 /// To query the client, you should use [`Self::query_self`].
115 ///
116 /// You can also use this to mutate data on an entity.
117 ///
118 /// # Panics
119 ///
120 /// This will panic if the entity doesn't exist or if the query isn't valid
121 /// for the entity. For a non-panicking version, you may use
122 /// [`Self::try_query_entity`].
123 pub fn query_entity<D: QueryData, R>(
124 &self,
125 entity: Entity,
126 f: impl FnOnce(QueryItem<D>) -> R,
127 ) -> R {
128 self.try_query_entity(entity, f).unwrap_or_else(|_| {
129 panic!(
130 "Querying entity {entity} failed when getting {:?}",
131 any::type_name::<D>()
132 )
133 })
134 }
135
136 /// A convenience function for getting components from any entity, or None
137 /// if the query fails.
138 ///
139 /// If you're sure that the entity exists and that the query will succeed,
140 /// you can use [`Self::query_entity`].
141 pub fn try_query_entity<D: QueryData, R>(
142 &self,
143 entity: Entity,
144 f: impl FnOnce(QueryItem<D>) -> R,
145 ) -> Result<R, QueryEntityError> {
146 let mut ecs = self.ecs.write();
147 let mut qs = ecs.query::<D>();
148 qs.get_mut(&mut ecs, entity).map(f)
149 }
150
151 /// Quickly returns an [`EntityRef`] for an arbitrary entity that
152 /// matches the given predicate function that is in the same
153 /// [`World`] as the client.
154 ///
155 /// [`World`]: azalea_world::World
156 pub fn any_entity_by<Q: QueryData, F: QueryFilter>(
157 &self,
158 predicate: impl EntityPredicate<Q, F>,
159 ) -> Option<EntityRef> {
160 self.any_entity_id_by(predicate)
161 .map(|e| self.entity_ref_for(e))
162 }
163 /// Quickly returns a lightweight [`Entity`] for an arbitrary entity that
164 /// matches the given predicate function that is in the same
165 /// [`World`] as the client.
166 ///
167 /// To get an [`EntityRef`], consider using [`Self::any_entity_by`]
168 /// instead.
169 ///
170 /// If you want to find the nearest entity, consider using
171 /// [`Self::nearest_entity_id_by`] instead. If you want to find all entities
172 /// that match the predicate, use [`Self::nearest_entity_ids_by`].
173 ///
174 /// # Example
175 ///
176 /// ```
177 /// use azalea::{entity::metadata::Player, player::GameProfileComponent};
178 /// use bevy_ecs::query::With;
179 ///
180 /// # fn example(mut bot: azalea::Client, sender_name: String) {
181 /// let entity = bot.any_entity_id_by::<&GameProfileComponent, With<Player>>(
182 /// |profile: &GameProfileComponent| profile.name == sender_name,
183 /// );
184 /// # }
185 /// ```
186 ///
187 /// [`World`]: azalea_world::World
188 pub fn any_entity_id_by<Q: QueryData, F: QueryFilter>(
189 &self,
190 predicate: impl EntityPredicate<Q, F>,
191 ) -> Option<Entity> {
192 let world_name = self.get_component::<WorldName>()?.clone();
193 predicate.find_any(self.ecs.clone(), &world_name)
194 }
195
196 /// Return an [`EntityRef`] for the nearest entity that matches the
197 /// given predicate function.
198 ///
199 /// If you don't need the entity to be the nearest one, it may be more
200 /// efficient to use [`Self::any_entity_by`] instead. You can also use
201 /// [`Self::nearest_entities_by`] to get all nearby entities.
202 ///
203 /// Also see [`Self::nearest_entity_id_by`] if you only need the lightweight
204 /// [`Entity`] identifier.
205 pub fn nearest_entity_by<Q: QueryData, F: QueryFilter>(
206 &self,
207 predicate: impl EntityPredicate<Q, F>,
208 ) -> Option<EntityRef> {
209 self.nearest_entity_id_by(predicate)
210 .map(|e| self.entity_ref_for(e))
211 }
212 /// Return a lightweight [`Entity`] for the nearest entity that matches the
213 /// given predicate function.
214 ///
215 /// To get an [`EntityRef`], consider using [`Self::nearest_entity_by`]
216 /// instead.
217 ///
218 /// If you don't need the entity to be the nearest one, it may be more
219 /// efficient to use [`Self::any_entity_id_by`] instead. You can also use
220 /// [`Self::nearest_entity_ids_by`] to get all nearby entities.
221 pub fn nearest_entity_id_by<Q: QueryData, F: QueryFilter>(
222 &self,
223 predicate: impl EntityPredicate<Q, F>,
224 ) -> Option<Entity> {
225 self.nearest_entity_ids_by(predicate).first().copied()
226 }
227
228 /// Returns an array of all [`EntityRef`]s in the world that match the
229 /// predicate, sorted by nearest first.
230 ///
231 /// To only get the nearest entity, consider using
232 /// [`Self::nearest_entity_by`]. If you only need the [`Entity`]
233 /// identifiers, you can use [`Self::nearest_entity_ids_by`] instead.
234 pub fn nearest_entities_by<Q: QueryData, F: QueryFilter>(
235 &self,
236 predicate: impl EntityPredicate<Q, F>,
237 ) -> Box<[EntityRef]> {
238 self.nearest_entity_ids_by(predicate)
239 .into_iter()
240 .map(|e| self.entity_ref_for(e))
241 .collect()
242 }
243 /// Returns an array of all [`Entity`]s in the world that match the
244 /// predicate, sorted by nearest first.
245 ///
246 /// To only get the nearest entity, consider using
247 /// [`Self::nearest_entity_id_by`]. To get the [`EntityRef`]s instead, you
248 /// can use [`Self::nearest_entities_by`].
249 ///
250 /// ```
251 /// # use azalea_entity::{LocalEntity, Position, metadata::Player};
252 /// # use bevy_ecs::query::{With, Without};
253 /// # fn example(mut bot: azalea::Client, sender_name: String) {
254 /// let nearby_players =
255 /// bot.nearest_entities_by::<(), (With<Player>, Without<LocalEntity>)>(|_: ()| true);
256 /// # }
257 /// ```
258 pub fn nearest_entity_ids_by<Q: QueryData, F: QueryFilter>(
259 &self,
260 predicate: impl EntityPredicate<Q, F>,
261 ) -> Box<[Entity]> {
262 let (world_name, position) = {
263 let Some(world_name) = self.get_component::<WorldName>() else {
264 return Box::new([]);
265 };
266 let Some(position) = self.get_component::<Position>() else {
267 return Box::new([]);
268 };
269
270 (world_name.clone(), **position)
271 };
272
273 predicate.find_all_sorted(self.ecs.clone(), &world_name, position)
274 }
275
276 /// Get a component from an entity.
277 ///
278 /// This allows you to access data stored about entities that isn't
279 /// accessible in a simpler way.
280 ///
281 /// This returns a reference to the component wrapped by a read guard. This
282 /// makes the component cheap to access, but means that the ECS cannot be
283 /// mutated while it's in scope. In some cases, it may be simpler for you to
284 /// immediately clone the component after accessing it.
285 ///
286 /// If you're trying to get a component for this client, you should use
287 /// [`Self::component`] instead.
288 ///
289 /// To do more complex queries or to mutate data, see
290 /// [`Self::query_entity`].
291 ///
292 /// # Panics
293 ///
294 /// This will panic if the component doesn't exist on the entity. Use
295 /// [`Self::get_entity_component`] to avoid this.
296 pub fn entity_component<T: Component>(&self, entity: Entity) -> MappedRwLockReadGuard<'_, T> {
297 self.get_entity_component::<T>(entity).unwrap_or_else(|| {
298 panic!(
299 "Entity {entity} is missing a required component: {:?}",
300 any::type_name::<&T>()
301 )
302 })
303 }
304
305 /// Get a component from an entity, if it exists.
306 ///
307 /// This is similar to [`Self::entity_component`] but returns an `Option`
308 /// instead of panicking if the component isn't present.
309 pub fn get_entity_component<T: Component>(
310 &self,
311 entity: Entity,
312 ) -> Option<MappedRwLockReadGuard<'_, T>> {
313 let ecs = self.ecs.read();
314 RwLockReadGuard::try_map(ecs, |ecs: &World| ecs.get(entity)).ok()
315 }
316}
317
318pub trait EntityPredicate<Q: QueryData, Filter: QueryFilter> {
319 fn find_any(&self, ecs_lock: Arc<RwLock<World>>, world_name: &WorldName) -> Option<Entity>;
320 fn find_all_sorted(
321 &self,
322 ecs_lock: Arc<RwLock<World>>,
323 world_name: &WorldName,
324 nearest_to: Vec3,
325 ) -> Box<[Entity]>;
326}
327impl<F, Q: QueryData, Filter: QueryFilter> EntityPredicate<Q, Filter> for F
328where
329 F: Fn(ROQueryItem<Q>) -> bool,
330 for<'w, 's> <<Q as QueryData>::ReadOnly as QueryData>::Item<'w, 's>: Copy,
331{
332 fn find_any(&self, ecs_lock: Arc<RwLock<World>>, world_name: &WorldName) -> Option<Entity> {
333 let mut ecs = ecs_lock.write();
334 let mut query = ecs.query_filtered::<(Entity, &WorldName, Q), Filter>();
335 query
336 .iter(&ecs)
337 .find(|(_, e_world_name, q)| *e_world_name == world_name && (self)(*q))
338 .map(|(e, _, _)| e)
339 }
340
341 fn find_all_sorted(
342 &self,
343 ecs_lock: Arc<RwLock<World>>,
344 world_name: &WorldName,
345 nearest_to: Vec3,
346 ) -> Box<[Entity]> {
347 let mut ecs = ecs_lock.write();
348 let mut query = ecs.query_filtered::<(Entity, &WorldName, &Position, Q), Filter>();
349 let mut entities = query
350 .iter(&ecs)
351 .filter(|(_, e_world_name, _, q)| *e_world_name == world_name && (self)(*q))
352 .map(|(e, _, position, _)| (e, Vec3::from(position)))
353 .collect::<Vec<(Entity, Vec3)>>();
354
355 entities.sort_by_cached_key(|(_, position)| {
356 // to_bits is fine here as long as the number is positive
357 position.distance_squared_to(nearest_to).to_bits()
358 });
359
360 entities
361 .into_iter()
362 .map(|(e, _)| e)
363 .collect::<Box<[Entity]>>()
364 }
365}