aboutsummaryrefslogtreecommitdiff
path: root/azalea-client/src/entity_query.rs
diff options
context:
space:
mode:
Diffstat (limited to 'azalea-client/src/entity_query.rs')
-rw-r--r--azalea-client/src/entity_query.rs100
1 files changed, 100 insertions, 0 deletions
diff --git a/azalea-client/src/entity_query.rs b/azalea-client/src/entity_query.rs
new file mode 100644
index 00000000..0e486741
--- /dev/null
+++ b/azalea-client/src/entity_query.rs
@@ -0,0 +1,100 @@
+use std::sync::Arc;
+
+use azalea_ecs::{
+ component::Component,
+ ecs::Ecs,
+ entity::Entity,
+ query::{ROQueryItem, ReadOnlyWorldQuery, WorldQuery},
+};
+use parking_lot::Mutex;
+
+use crate::Client;
+
+impl Client {
+ /// A convenience function for getting components of our player's entity.
+ pub fn query<'w, Q: WorldQuery>(&self, ecs: &'w mut Ecs) -> <Q as WorldQuery>::Item<'w> {
+ ecs.query::<Q>()
+ .get_mut(ecs, self.entity)
+ .expect("Our client is missing a required component.")
+ }
+
+ /// 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 azalea_ecs::query::With;
+ /// use azalea_world::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);
+ /// // ...
+ /// }
+ /// # }
+ /// ```
+ pub fn entity_by<F: ReadOnlyWorldQuery, Q: ReadOnlyWorldQuery>(
+ &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)
+ .expect("Entity components must be present in Client::entity)components.");
+ components.clone()
+ }
+}
+
+pub trait EntityPredicate<Q: ReadOnlyWorldQuery, Filter: ReadOnlyWorldQuery> {
+ fn find(&self, ecs_lock: Arc<Mutex<Ecs>>) -> Option<Entity>;
+}
+impl<F, Q, Filter> EntityPredicate<(Q,), Filter> for F
+where
+ F: Fn(&ROQueryItem<Q>) -> bool,
+ Q: ReadOnlyWorldQuery,
+ Filter: ReadOnlyWorldQuery,
+{
+ fn find(&self, ecs_lock: Arc<Mutex<Ecs>>) -> 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: ReadOnlyWorldQuery,
+// Q2: ReadOnlyWorldQuery,
+// {
+// 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
+// }
+// }