azalea_client/entity_query.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
use std::sync::Arc;
use bevy_ecs::{
component::Component,
entity::Entity,
query::QueryData,
query::{QueryFilter, ROQueryItem},
world::World,
};
use parking_lot::Mutex;
use crate::Client;
impl Client {
/// A convenience function for getting components of our player's entity.
///
/// # Examples
/// ```
/// # use azalea_world::InstanceName;
/// # fn example(mut client: azalea_client::Client) {
/// let is_logged_in = client
/// .query::<Option<&InstanceName>>(&mut client.ecs.lock())
/// .is_some();
/// # }
/// ```
pub fn query<'w, D: QueryData>(&self, ecs: &'w mut World) -> D::Item<'w> {
ecs.query::<D>()
.get_mut(ecs, self.entity)
.unwrap_or_else(|_| {
panic!(
"Our client is missing a required component {:?}",
std::any::type_name::<D>()
)
})
}
/// Return a lightweight [`Entity`] for the entity that matches the given
/// predicate function.
///
/// You can then use [`Self::entity_component`] to get components from this
/// entity.
///
/// # Example
/// Note that this will very likely change in the future.
/// ```
/// use azalea_client::{Client, GameProfileComponent};
/// use bevy_ecs::query::With;
/// use azalea_entity::{Position, metadata::Player};
///
/// # fn example(mut bot: Client, sender_name: String) {
/// let entity = bot.entity_by::<With<Player>, (&GameProfileComponent,)>(
/// |(profile,): &(&GameProfileComponent,)| profile.name == sender_name,
/// );
/// if let Some(entity) = entity {
/// let position = bot.entity_component::<Position>(entity);
/// // ...
/// }
/// # }
/// ```
///
/// [`Entity`]: bevy_ecs::entity::Entity
pub fn entity_by<F: QueryFilter, Q: QueryData>(
&mut self,
predicate: impl EntityPredicate<Q, F>,
) -> Option<Entity> {
predicate.find(self.ecs.clone())
}
/// Get a component from an entity. Note that this will return an owned type
/// (i.e. not a reference) so it may be expensive for larger types.
///
/// If you're trying to get a component for this client, use
/// [`Self::component`].
pub fn entity_component<Q: Component + Clone>(&mut self, entity: Entity) -> Q {
let mut ecs = self.ecs.lock();
let mut q = ecs.query::<&Q>();
let components = q.get(&ecs, entity).unwrap_or_else(|_| {
panic!(
"Entity is missing a required component {:?}",
std::any::type_name::<Q>()
)
});
components.clone()
}
/// Get a component from an entity, if it exists. This is similar to
/// [`Self::entity_component`] but returns an `Option` instead of panicking
/// if the component isn't present.
pub fn get_entity_component<Q: Component + Clone>(&mut self, entity: Entity) -> Option<Q> {
let mut ecs = self.ecs.lock();
let mut q = ecs.query::<&Q>();
let components = q.get(&ecs, entity).ok();
components.cloned()
}
}
pub trait EntityPredicate<Q: QueryData, Filter: QueryFilter> {
fn find(&self, ecs_lock: Arc<Mutex<World>>) -> Option<Entity>;
}
impl<F, Q, Filter> EntityPredicate<Q, Filter> for F
where
F: Fn(&ROQueryItem<Q>) -> bool,
Q: QueryData,
Filter: QueryFilter,
{
fn find(&self, ecs_lock: Arc<Mutex<World>>) -> Option<Entity> {
let mut ecs = ecs_lock.lock();
let mut query = ecs.query_filtered::<(Entity, Q), Filter>();
let entity = query.iter(&ecs).find(|(_, q)| (self)(q)).map(|(e, _)| e);
entity
}
}
// impl<'a, F, Q1, Q2> EntityPredicate<'a, (Q1, Q2)> for F
// where
// F: Fn(&<Q1 as WorldQuery>::Item<'_>, &<Q2 as WorldQuery>::Item<'_>) ->
// bool, Q1: QueryFilter,
// Q2: QueryFilter,
// {
// fn find(&self, ecs: &mut Ecs) -> Option<Entity> {
// // (self)(query)
// let mut query = ecs.query_filtered::<(Entity, Q1, Q2), ()>();
// let entity = query
// .iter(ecs)
// .find(|(_, q1, q2)| (self)(q1, q2))
// .map(|(e, _, _)| e);
// entity
// }
// }