aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormat <git@matdoes.dev>2025-06-01 09:57:54 -1245
committermat <git@matdoes.dev>2025-06-01 09:57:54 -1245
commit1d3a7c969f430a8cea4296930df0d6c04e253747 (patch)
treec30eeba985e577fe798b416d4282f9c561d9d537
parentd028d7c3e9c84d177b7b10fa0d8f77d11bcea20f (diff)
downloadazalea-drasl-1d3a7c969f430a8cea4296930df0d6c04e253747.tar.xz
add Client::entities_by and improve some docs
-rw-r--r--azalea-client/src/entity_query.rs75
-rw-r--r--azalea-client/src/plugins/chat/mod.rs6
-rw-r--r--azalea-world/src/container.rs6
-rw-r--r--azalea-world/src/world.rs8
-rw-r--r--azalea/src/pathfinder/mod.rs4
5 files changed, 63 insertions, 36 deletions
diff --git a/azalea-client/src/entity_query.rs b/azalea-client/src/entity_query.rs
index 1f2ff080..409253a3 100644
--- a/azalea-client/src/entity_query.rs
+++ b/azalea-client/src/entity_query.rs
@@ -1,5 +1,6 @@
use std::{any, sync::Arc};
+use azalea_world::InstanceName;
use bevy_ecs::{
component::Component,
entity::Entity,
@@ -33,14 +34,14 @@ impl Client {
})
}
- /// Return a lightweight [`Entity`] for the entity that matches the given
- /// predicate function.
+ /// Return a lightweight [`Entity`] for the first 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.
///
/// # Example
- /// Note that this will very likely change in the future.
/// ```
/// use azalea_client::{Client, GameProfileComponent};
/// use azalea_entity::{Position, metadata::Player};
@@ -58,11 +59,25 @@ impl Client {
/// ```
///
/// [`Entity`]: bevy_ecs::entity::Entity
+ /// [`Instance`]: azalea_world::Instance
pub fn entity_by<F: QueryFilter, Q: QueryData>(
&self,
predicate: impl EntityPredicate<Q, F>,
) -> Option<Entity> {
- predicate.find(self.ecs.clone())
+ let instance_name = self.get_component::<InstanceName>()?;
+ predicate.find(self.ecs.clone(), &instance_name)
+ }
+
+ /// Same as [`Self::entity_by`] but returns a `Vec<Entity>` of all entities
+ /// in our instance that match the predicate.
+ pub fn entities_by<F: QueryFilter, Q: QueryData>(
+ &self,
+ predicate: impl EntityPredicate<Q, F>,
+ ) -> Vec<Entity> {
+ let Some(instance_name) = self.get_component::<InstanceName>() else {
+ return vec![];
+ };
+ predicate.find_all(self.ecs.clone(), &instance_name)
}
/// Get a component from an entity. Note that this will return an owned type
@@ -94,35 +109,37 @@ impl Client {
}
pub trait EntityPredicate<Q: QueryData, Filter: QueryFilter> {
- fn find(&self, ecs_lock: Arc<Mutex<World>>) -> Option<Entity>;
+ fn find(&self, ecs_lock: Arc<Mutex<World>>, instance_name: &InstanceName) -> Option<Entity>;
+ fn find_all<'a>(
+ &'a self,
+ ecs_lock: Arc<Mutex<World>>,
+ instance_name: &InstanceName,
+ ) -> Vec<Entity>;
}
-impl<F, Q, Filter> EntityPredicate<Q, Filter> for F
+impl<F, Q: QueryData, Filter: QueryFilter> 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> {
+ fn find(&self, ecs_lock: Arc<Mutex<World>>, instance_name: &InstanceName) -> Option<Entity> {
let mut ecs = ecs_lock.lock();
- let mut query = ecs.query_filtered::<(Entity, Q), Filter>();
- query.iter(&ecs).find(|(_, q)| (self)(q)).map(|(e, _)| e)
+ let mut query = ecs.query_filtered::<(Entity, &InstanceName, Q), Filter>();
+ query
+ .iter(&ecs)
+ .find(|(_, e_instance_name, q)| *e_instance_name == instance_name && (self)(q))
+ .map(|(e, _, _)| e)
}
-}
-// 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
-// }
-// }
+ fn find_all<'a>(
+ &'a self,
+ ecs_lock: Arc<Mutex<World>>,
+ instance_name: &InstanceName,
+ ) -> Vec<Entity> {
+ let mut ecs = ecs_lock.lock();
+ let mut query = ecs.query_filtered::<(Entity, &InstanceName, Q), Filter>();
+ query
+ .iter(&ecs)
+ .filter(|(_, e_instance_name, q)| *e_instance_name == instance_name && (self)(q))
+ .map(|(e, _, _)| e)
+ .collect::<Vec<_>>()
+ }
+}
diff --git a/azalea-client/src/plugins/chat/mod.rs b/azalea-client/src/plugins/chat/mod.rs
index 7d42eb20..603dea60 100644
--- a/azalea-client/src/plugins/chat/mod.rs
+++ b/azalea-client/src/plugins/chat/mod.rs
@@ -124,9 +124,9 @@ impl ChatPacket {
}))
}
- /// Whether this message was sent with /msg (or aliases). It works by
- /// checking the translation key, so it won't work on servers that use their
- /// own whisper system.
+ /// Whether this message is an incoming whisper message (i.e. someone else
+ /// dm'd the bot with /msg). It works by checking the translation key, so it
+ /// won't work on servers that use their own whisper system.
pub fn is_whisper(&self) -> bool {
match self.message() {
FormattedText::Text(_) => false,
diff --git a/azalea-world/src/container.rs b/azalea-world/src/container.rs
index 53b9c784..bb8ade70 100644
--- a/azalea-world/src/container.rs
+++ b/azalea-world/src/container.rs
@@ -58,7 +58,7 @@ impl InstanceContainer {
let existing = existing_lock.read();
if existing.chunks.height != height {
error!(
- "Shared dimension height mismatch: {} != {height}",
+ "Shared world height mismatch: {} != {height}",
existing.chunks.height
);
}
@@ -86,8 +86,8 @@ impl InstanceContainer {
}
/// The name of the [`Instance`](crate::Instance) (world) the entity is
-/// in. If two entities share the same world name, we assume they're in the same
-/// instance.
+/// in. If two entities share the same instance name, we assume they're in the
+/// same instance.
#[derive(Component, Clone, Debug, PartialEq, Deref, DerefMut)]
#[doc(alias("worldname", "world name"))]
pub struct InstanceName(pub ResourceLocation);
diff --git a/azalea-world/src/world.rs b/azalea-world/src/world.rs
index 00bee13a..47804dcc 100644
--- a/azalea-world/src/world.rs
+++ b/azalea-world/src/world.rs
@@ -144,6 +144,14 @@ impl PartialEntityInfos {
/// A world where the chunks are stored as weak pointers. This is used for
/// shared worlds.
+///
+/// Also see [`PartialInstance`].
+///
+/// The reason this is called "instance" instead of "world" or "dimension" is
+/// because "world" already means the entire ECS (which can contain multiple
+/// instances if we're in a swarm) and "dimension" can be ambiguous (for
+/// instance there can be multiple overworlds, and "dimension" is also a math
+/// term)
#[derive(Default, Debug)]
pub struct Instance {
pub chunks: ChunkStorage,
diff --git a/azalea/src/pathfinder/mod.rs b/azalea/src/pathfinder/mod.rs
index 1b8a71c8..12b6f156 100644
--- a/azalea/src/pathfinder/mod.rs
+++ b/azalea/src/pathfinder/mod.rs
@@ -142,7 +142,7 @@ pub struct GotoEvent {
pub entity: Entity,
pub goal: Arc<dyn Goal>,
/// The function that's used for checking what moves are possible. Usually
- /// `pathfinder::moves::default_move`
+ /// [`moves::default_move`].
pub successors_fn: SuccessorsFn,
/// Whether the bot is allowed to break blocks while pathfinding.
@@ -198,6 +198,8 @@ impl PathfinderClientExt for azalea_client::Client {
/// Pathfind to the given goal and wait until either the target is reached
/// or the pathfinding is canceled.
///
+ /// You can use [`Self::start_goto`] instead if you don't want to wait.
+ ///
/// ```
/// # use azalea::prelude::*;
/// # use azalea::{BlockPos, pathfinder::goals::BlockPosGoal};